A kinda passing test
This commit is contained in:
parent
8be123440d
commit
9630691d13
10 changed files with 175 additions and 22 deletions
|
@ -1,9 +1,12 @@
|
|||
using Microsoft.VisualBasic;
|
||||
using LibHac.FsSystem;
|
||||
using Microsoft.FSharp.Core;
|
||||
using Microsoft.VisualBasic;
|
||||
using NUnit.Framework;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.Graphics.Texture.Astc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
@ -18,15 +21,20 @@ namespace Ryujinx.Tests.Graphics
|
|||
* HOW I GENERATED INPUT DATA
|
||||
* Step 1. Create ASTC-compressed image from sample data.
|
||||
* *** NOTE This image isn't 2^x evenly sized, it's 768x512 - something that would break down into nice squares, for sure.
|
||||
* `bin/astcenc-avx2 -cl sources/kodim01.png output/kodim01.l4x4.astc 4x4 -fast`
|
||||
* `astcenc-sse2 -cl MoreRocks.png MoreRocks.l-4x4-100.astc 4x4 100`
|
||||
*
|
||||
* Step 2. Decompress the data we just created.
|
||||
* `bin/astcenc-avx2 -dl output/kodim01.l4x4.astc output/kodim01.l4x4.astc.png`
|
||||
* `astcenc-sse2 -dl MoreRocks.l-4x4-100.astc MoreRocks.l-4x4-100.astc.png`
|
||||
*
|
||||
* Step 3.
|
||||
* I used convertio to convert the PNG generated in step 2 to create MorRocks.l-4x4-100.astc.rgba
|
||||
|
||||
* WHAT WE DO IN THE TEST BELOW:
|
||||
* 1. Read the sample iamge, ASTC-compressed reference, and decompressed reference that we generated above.
|
||||
* 1. Read the sample image, ASTC-compressed reference, and decompressed reference that we generated above.
|
||||
* 2. Run TryDecodeToRgba8P on our ASTC-compressed texture.
|
||||
* 2a. Write the output of step 2 to the disk.
|
||||
* 3. Assert that the data we decompressed in our method is the same data as the decompressed reference image.
|
||||
*
|
||||
*/
|
||||
|
||||
public class AstcDecoderTests
|
||||
|
@ -42,41 +50,84 @@ namespace Ryujinx.Tests.Graphics
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void _Test()
|
||||
public void Simple_Test()
|
||||
{
|
||||
GraphicsConfig.EnableTextureRecompression = false;
|
||||
/// This test doesn't do anything particularly tricky.
|
||||
|
||||
var (original, encodedRef, decodedRef) = _getTestDataTupleFromShortname("kodim01");
|
||||
GraphicsConfig.EnableTextureRecompression = false;
|
||||
int blockWidth = 4;
|
||||
int blockHeight = 4;
|
||||
|
||||
int texWidth = 768;
|
||||
int texHeight = 512;
|
||||
var (original, encodedRef, decodedRef) = _getTestDataTupleFromShortname("MoreRocks", blockWidth, blockHeight);
|
||||
int astcHeaderLength = 16;
|
||||
|
||||
// skip the header. Decode method doesn't work without this and will return false.
|
||||
var rawastc = encodedRef.Slice(astcHeaderLength, encodedRef.Length - astcHeaderLength);
|
||||
|
||||
int texWidth = 256;
|
||||
int texHeight = 256;
|
||||
byte[] outputBuffer = Array.Empty<byte>();
|
||||
|
||||
int depth = 1;
|
||||
int levels = 1;
|
||||
int layers = 1;
|
||||
|
||||
_ = AstcDecoder.TryDecodeToRgba8P(encodedRef, blockWidth, blockHeight, texWidth, texHeight, depth, levels, layers, out outputBuffer);
|
||||
var outputPath = Path.Join(_testDataDir, "kodim01.l4x4.output.png");
|
||||
bool succeeded = AstcDecoder.TryDecodeToRgba8P(rawastc, blockWidth, blockHeight, texWidth, texHeight, depth, levels, layers, out outputBuffer);
|
||||
var outputPath = Path.Join(_testDataDir, "output-MoreRocks.l-4x4-100.astc.rgba8");
|
||||
|
||||
// Make sure we're clobbering the test output.
|
||||
if (File.Exists(outputPath))
|
||||
File.Delete(outputPath);
|
||||
File.WriteAllBytes(outputPath, outputBuffer);
|
||||
|
||||
Assert.AreEqual(decodedRef, outputBuffer);
|
||||
// The decode function said it was valid data and that it could parse it.
|
||||
Assert.AreEqual(true, succeeded);
|
||||
// Length is the same as the one we made w/ ARM's decoder. That's good.
|
||||
Assert.AreEqual(decodedRef.Length, outputBuffer.Length);
|
||||
|
||||
var wordsRef = toWords(decodedRef.ToArray());
|
||||
var wordsOut = toWords(outputBuffer);
|
||||
var wordDifferences = wordsRef.Select((x, i) => new { index = i, diff = x.Diff(wordsOut[i]) }).ToArray();
|
||||
|
||||
// BUT compression is funny.
|
||||
// Calculate the byte differences.
|
||||
var byteDifferences = decodedRef.ToArray().Select((x, i) => new { index = i, delta = x - outputBuffer[i] }).ToList();
|
||||
|
||||
var matchCount = byteDifferences.Count(x => x.delta == 0);
|
||||
var matchPercent = ((float)matchCount / outputBuffer.Length);
|
||||
|
||||
var wordUnchangedCount = wordDifferences.Count(x => x.diff.IsZero());
|
||||
var wordUnchangedPercent = (float)wordUnchangedCount / wordDifferences.Count();
|
||||
|
||||
Debug.WriteLine($"Pixel-wise comparison: {wordUnchangedPercent * 100:F4} ({wordUnchangedCount}/{wordDifferences.Length})");
|
||||
Debug.WriteLine($"Byte-wise comparison{matchPercent * 100:F4} ({matchCount}/{byteDifferences.Count}) were same.");
|
||||
|
||||
for (var threshold = 1; threshold< 16; threshold++)
|
||||
{
|
||||
var tc = byteDifferences.Count(x => Math.Abs(x.delta) >= threshold);
|
||||
var tcp = ((float)tc / byteDifferences.Count);
|
||||
Debug.WriteLine($"{tcp*100:F4}% ({tc}/{byteDifferences.Count}) are different by at least {threshold}.");
|
||||
}
|
||||
|
||||
private (ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>) _getTestDataTupleFromShortname(string shortName)
|
||||
Assert.IsTrue(byteDifferences.All(x => Math.Abs(x.delta) <= 2));
|
||||
Assert.IsTrue(decodedRef.Equals(outputBuffer));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get test data from FS using short name naming convention.
|
||||
/// </summary>
|
||||
/// <param name="shortName"></param>
|
||||
/// <returns></returns>
|
||||
private (ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>) _getTestDataTupleFromShortname(string shortName, int blockWidth, int blockHeight)
|
||||
{
|
||||
var original = _getFileDataFromPath($"{shortName}.png");
|
||||
// TODO: add brains for block sizes/etc
|
||||
var encodedRef = _getFileDataFromPath($"{shortName}.l4x4.astc");
|
||||
var decodedRef = _getFileDataFromPath($"{shortName}.l4x4.astc.png");
|
||||
|
||||
return (original, encodedRef, decodedRef);
|
||||
var encodedRef = _getFileDataFromPath($"{shortName}.l-{blockWidth}x{blockHeight}-100.astc");
|
||||
// var decodedRef = _getFileDataFromPath($"{shortName}.s4x4.astc.png");
|
||||
var rgba8raw = _getFileDataFromPath($"{shortName}.l-{blockWidth}x{blockHeight}-100.astc.rgba");
|
||||
|
||||
return (original, encodedRef, rgba8raw);
|
||||
}
|
||||
|
||||
private ReadOnlyMemory<byte> _getFileDataFromPath(string relativeFilePath)
|
||||
|
@ -85,6 +136,61 @@ namespace Ryujinx.Tests.Graphics
|
|||
return File.ReadAllBytes(fullPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return an array of RGBA words given an array of bytes.
|
||||
/// </summary>
|
||||
/// <param name="rawBytes"></param>
|
||||
/// <returns></returns>
|
||||
private RgbaWord[] toWords(byte[] rawBytes)
|
||||
{
|
||||
var result = new List<RgbaWord>();
|
||||
// rawbytes has to be factor-of-4-sized.
|
||||
for (var i = 0; i < rawBytes.Length; i += 4)
|
||||
{
|
||||
result.Add(new RgbaWord()
|
||||
{
|
||||
r = rawBytes[i],
|
||||
g = rawBytes[i + 1],
|
||||
b = rawBytes[i + 2],
|
||||
a = rawBytes[i + 3]
|
||||
}) ;
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
private class RgbaWord
|
||||
{
|
||||
public byte r;
|
||||
public byte g;
|
||||
public byte b;
|
||||
public byte a;
|
||||
|
||||
public bool IsZero()
|
||||
{
|
||||
return r == 0 && g == 0 && b == 0 && a == 0;
|
||||
}
|
||||
|
||||
public bool SameAs(RgbaWord other)
|
||||
{
|
||||
return this.r == other.r && this.g == other.g && this.b == other.b && this.a == other.a;
|
||||
}
|
||||
|
||||
public RgbaWord Diff(RgbaWord other)
|
||||
{
|
||||
/*
|
||||
|
||||
Returns 0 for a field if equal and absolute value of diff if not.
|
||||
|
||||
|
||||
*/
|
||||
return new RgbaWord()
|
||||
{
|
||||
r = (byte)Math.Abs(this.r - other.r),
|
||||
g = (byte)Math.Abs(this.g - other.g),
|
||||
b = (byte)Math.Abs(this.b - other.b),
|
||||
a = (byte)Math.Abs(this.a - other.a)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
BIN
src/Ryujinx.Tests/Graphics/TestData/MoreRocks.l-4x4-100.astc
Normal file
BIN
src/Ryujinx.Tests/Graphics/TestData/MoreRocks.l-4x4-100.astc
Normal file
Binary file not shown.
BIN
src/Ryujinx.Tests/Graphics/TestData/MoreRocks.l-4x4-100.astc.png
Normal file
BIN
src/Ryujinx.Tests/Graphics/TestData/MoreRocks.l-4x4-100.astc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 193 KiB |
File diff suppressed because one or more lines are too long
BIN
src/Ryujinx.Tests/Graphics/TestData/MoreRocks.png
Normal file
BIN
src/Ryujinx.Tests/Graphics/TestData/MoreRocks.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 140 KiB |
BIN
src/Ryujinx.Tests/Graphics/TestData/astcenc-sse2.exe
Normal file
BIN
src/Ryujinx.Tests/Graphics/TestData/astcenc-sse2.exe
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 985 KiB |
Binary file not shown.
Before Width: | Height: | Size: 719 KiB |
|
@ -34,15 +34,57 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Graphics\TestData\astcenc-sse2.exe">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\diff.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\kodim01.l4x4.astc">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\kodim01.l4x4.astc.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\kodim01.l4x4.astc.tga">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\kodim01.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\kodim01.png.output.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\kodim01.rgba">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.l-4x4-100.astc">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.l-4x4-100.astc.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.l-4x4-100.astc.rgba">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.s4x4.astc">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.s4x4.astc.png">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.s4x4.astc.png.rgba">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.s4x4.astc.rgba">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Graphics\TestData\MoreRocks.s4x4.astc.tga">
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyUnicorn" AfterTargets="Build">
|
||||
|
|
Loading…
Reference in a new issue