4x4 test passes, 5x5 test fails

This commit is contained in:
Michael Durrant 2023-06-15 22:38:01 -06:00
parent 3884ffa628
commit 1e01c8b7c2

View file

@ -4,6 +4,7 @@ using Microsoft.VisualBasic;
using NUnit.Framework; using NUnit.Framework;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Texture.Astc; using Ryujinx.Graphics.Texture.Astc;
using Ryujinx.HLE.HOS.Services.SurfaceFlinger;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -47,18 +48,15 @@ namespace Ryujinx.Tests.Graphics
{ {
_workingDir = TestContext.CurrentContext.TestDirectory; _workingDir = TestContext.CurrentContext.TestDirectory;
_testDataDir = Path.Join(_workingDir, "Graphics", "TestData"); _testDataDir = Path.Join(_workingDir, "Graphics", "TestData");
GraphicsConfig.EnableTextureRecompression = false;
} }
[Test] // public void
public void Simple_Test() [TestCase(4, 4)]
[TestCase(5, 5)]
public void Paramterized_BlockSizes_Test(int blockWidth, int blockHeight)
{ {
/// This test doesn't do anything particularly tricky. var (encodedRef, decodedRef) = _getTestDataTupleFromShortname("MoreRocks", blockWidth, blockHeight);
GraphicsConfig.EnableTextureRecompression = false;
int blockWidth = 4;
int blockHeight = 4;
var (original, encodedRef, decodedRef) = _getTestDataTupleFromShortname("MoreRocks", blockWidth, blockHeight);
int astcHeaderLength = 16; int astcHeaderLength = 16;
// skip the header. Decode method doesn't work without this and will return false. // skip the header. Decode method doesn't work without this and will return false.
@ -73,20 +71,15 @@ namespace Ryujinx.Tests.Graphics
int layers = 1; int layers = 1;
bool succeeded = AstcDecoder.TryDecodeToRgba8P(rawastc, blockWidth, blockHeight, texWidth, texHeight, depth, levels, layers, out outputBuffer); 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);
// The decode function said it was valid data and that it could parse it. // The decode function said it was valid data and that it could parse it.
Assert.AreEqual(true, succeeded); Assert.AreEqual(true, succeeded);
// Length is the same as the one we made w/ ARM's decoder. That's good. // Length is the same as the one we made w/ ARM's decoder. That's good.
Assert.AreEqual(decodedRef.Length, outputBuffer.Length); Assert.AreEqual(decodedRef.Length, outputBuffer.Length);
var wordsRef = toWords(decodedRef.ToArray()); var wordsRef = RgbaWord.FromBytes(decodedRef.ToArray());
var wordsOut = toWords(outputBuffer); var wordsOut = RgbaWord.FromBytes(outputBuffer);
var wordDifferences = wordsRef.Select((x, i) => new { index = i, diff = x.Diff(wordsOut[i]) }).ToArray(); var wordDifferences = wordsRef.Select((x, i) => new { index = i, diff = x.Diff(wordsOut[i]) }).ToArray();
// BUT compression is funny. // BUT compression is funny.
@ -100,7 +93,62 @@ namespace Ryujinx.Tests.Graphics
var wordUnchangedPercent = (float)wordUnchangedCount / wordDifferences.Count(); var wordUnchangedPercent = (float)wordUnchangedCount / wordDifferences.Count();
Debug.WriteLine($"Pixel-wise comparison: {wordUnchangedPercent * 100:F4} ({wordUnchangedCount}/{wordDifferences.Length})"); Debug.WriteLine($"Pixel-wise comparison: {wordUnchangedPercent * 100:F4} ({wordUnchangedCount}/{wordDifferences.Length})");
Debug.WriteLine($"Byte-wise comparison{matchPercent * 100:F4} ({matchCount}/{byteDifferences.Count}) were same."); 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}.");
}
Assert.IsTrue(byteDifferences.All(x => Math.Abs(x.delta) < 2));
}
public void _Linear_4x4_Static_Test()
{
/// This test doesn't do anything particularly tricky.
GraphicsConfig.EnableTextureRecompression = false;
int blockWidth = 4;
int blockHeight = 4;
var (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;
bool succeeded = AstcDecoder.TryDecodeToRgba8P(rawastc, blockWidth, blockHeight, texWidth, texHeight, depth, levels, layers, out 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 = RgbaWord.FromBytes(decodedRef.ToArray());
var wordsOut = RgbaWord.FromBytes(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++) for (var threshold = 1; threshold< 16; threshold++)
{ {
@ -117,16 +165,13 @@ namespace Ryujinx.Tests.Graphics
/// </summary> /// </summary>
/// <param name="shortName"></param> /// <param name="shortName"></param>
/// <returns></returns> /// <returns></returns>
private (ReadOnlyMemory<byte>, ReadOnlyMemory<byte>, ReadOnlyMemory<byte>) _getTestDataTupleFromShortname(string shortName, int blockWidth, int blockHeight) private (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}.l-{blockWidth}x{blockHeight}-100.astc"); var encodedRef = _getFileDataFromPath($"{shortName}.l-{blockWidth}x{blockHeight}-100.astc");
// var decodedRef = _getFileDataFromPath($"{shortName}.s4x4.astc.png"); // var decodedRef = _getFileDataFromPath($"{shortName}.s4x4.astc.png");
var rgba8raw = _getFileDataFromPath($"{shortName}.l-{blockWidth}x{blockHeight}-100.astc.rgba"); var rgba8raw = _getFileDataFromPath($"{shortName}.l-{blockWidth}x{blockHeight}-100.astc.rgba");
return (original, encodedRef, rgba8raw); return (encodedRef, rgba8raw);
} }
private ReadOnlyMemory<byte> _getFileDataFromPath(string relativeFilePath) private ReadOnlyMemory<byte> _getFileDataFromPath(string relativeFilePath)
@ -135,28 +180,6 @@ namespace Ryujinx.Tests.Graphics
return File.ReadAllBytes(fullPath); 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 private class RgbaWord
{ {
public byte r; public byte r;
@ -190,6 +213,28 @@ namespace Ryujinx.Tests.Graphics
a = (byte)Math.Abs(this.a - other.a) a = (byte)Math.Abs(this.a - other.a)
}; };
} }
/// <summary>
/// Return an array of RGBA words given an array of bytes.
/// </summary>
/// <param name="rawBytes"></param>
/// <returns></returns>
public static RgbaWord[] FromBytes(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();
}
} }
} }
} }