XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using XFESystem.Desktop;
using XFESystem.Platform;

namespace XFESystem.Platform.Tests;

public sealed class FramebufferTests
{
    [Theory]
    [InlineData(32, 0x00FF0000u, 0x0000FF00u, 0x000000FFu, 0x00FF0000u, 0x0000FF00u, 0x000000FFu)]
    [InlineData(24, 0x000000FFu, 0x0000FF00u, 0x00FF0000u, 0x000000FFu, 0x0000FF00u, 0x00FF0000u)]
    [InlineData(16, 0x0000F800u, 0x000007E0u, 0x0000001Fu, 0x0000F800u, 0x000007E0u, 0x0000001Fu)]
    public unsafe void MappedScanoutUsesRgbMasksPitchAndLeavesGuardBytesUntouched(int bits, uint redMask, uint greenMask, uint blueMask, uint red, uint green, uint blue)
    {
        const int width = 3, height = 2;
        int bytes = bits / 8, pitch = width * bytes + 5;
        var scanout = Enumerable.Repeat((byte)0xA5, pitch * height + 16).ToArray();
        int[] pixels = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFFFF, 0, 0xFFFFFF];
        fixed (byte* address = scanout)
        {
            var target = new MemoryFramebufferPresenter(new((nuint)address, (nuint)(pitch * height), width, height, pitch, bits, redMask, greenMask, blueMask));
            target.Present(pixels, new(-20, -20, 23, 21));
        }
        uint Read(int pixel) { uint value = 0; for (int b = 0; b < bytes; b++) value |= (uint)scanout[pixel * bytes + b] << (8 * b); return value; }
        Assert.Equal(red, Read(0)); Assert.Equal(green, Read(1)); Assert.Equal(blue, Read(2));
        Assert.All(scanout.Skip(width * bytes), value => Assert.Equal(0xA5, value));
    }

    [Fact]
    public unsafe void InvalidMappingAndMasksAreRejectedBeforeAnyWrite()
    {
        var data = new byte[64];
        fixed (byte* p = data)
        {
            nuint address = (nuint)p;
            Assert.Throws<ArgumentException>(() => new MemoryFramebufferPresenter(new(address, 4, 3, 2, 16, 32, 0xFF0000, 0xFF00, 0xFF)));
            Assert.Throws<ArgumentException>(() => new MemoryFramebufferPresenter(new(address, 64, 3, 2, 8, 32, 0xFF0000, 0xFF00, 0xFF)));
            Assert.Throws<ArgumentException>(() => new MemoryFramebufferPresenter(new(address, 64, 3, 2, 16, 32, 0xFF00, 0xFF00, 0xFF)));
            Assert.Throws<ArgumentException>(() => new MemoryFramebufferPresenter(new(address, 64, 3, 2, 16, 32, 0xA00000, 0xFF00, 0xFF)));
        }
        Assert.All(data, value => Assert.Equal(0, value));
    }

    [Fact]
    public void CoverageBlendsAgainstExistingPixelsAndHonorsNestedClipping()
    {
        var output = new ArrayFramebufferPresenter(8, 8); var canvas = new CpuFramebufferCanvas(output);
        canvas.Fill(0x0000FF, 0, 0, 8, 8);
        canvas.PushClip(new(2, 2, 3, 3)); canvas.PushClip(new(3, 1, 3, 3));
        canvas.BlendCoverage(0xFF0000, 0, 0, 8, 8, Enumerable.Repeat((byte)128, 64).ToArray());
        canvas.PopClip(); canvas.PopClip(); canvas.Present();
        Assert.Equal(0x80007F, output.Pixels.Span[2 * 8 + 3]);
        Assert.Equal(0x0000FF, output.Pixels.Span[2 * 8 + 2]);
        Assert.Equal(0x0000FF, output.Pixels.Span[4 * 8 + 3]);
        Assert.Throws<InvalidOperationException>(canvas.PopClip);
        Assert.Throws<ArgumentException>(() => canvas.BlendCoverage(0, 0, 0, 8, 8, new byte[63]));
    }

    [Fact]
    public void FullPresentationIncludesNativeRemainderAtFractionalScale()
    {
        var output = new ArrayFramebufferPresenter(11, 9); var canvas = new CpuFramebufferCanvas(output, scalePercent: 125);
        canvas.Fill(0x123456, 0, 0, canvas.Width, canvas.Height); canvas.Present();
        Assert.All(output.Pixels.ToArray(), pixel => Assert.Equal(0x123456, pixel));
    }

    [Fact]
    public void EmptyFillAtFractionalLayoutEdgeDoesNotPaintNativeRemainder()
    {
        var output = new ArrayFramebufferPresenter(11, 9); var canvas = new CpuFramebufferCanvas(output, scalePercent: 125);
        canvas.Fill(0x123456, canvas.Width, 0, 0, canvas.Height);
        canvas.Fill(0xFFFFFF, 0, 0, -1, canvas.Height); canvas.Present();
        Assert.All(output.Pixels.ToArray(), pixel => Assert.Equal(0, pixel));
    }

    [Fact]
    public void HugeLineEndpointsAreClippedBeforeWalkingPixels()
    {
        var output = new ArrayFramebufferPresenter(8, 8); var canvas = new CpuFramebufferCanvas(output);
        canvas.Line(0xFFFFFF, int.MinValue, 3, int.MaxValue, 3); canvas.Present();
        Assert.All(output.Pixels.Slice(24, 8).ToArray(), pixel => Assert.Equal(0xFFFFFF, pixel));
        Assert.Equal(8, output.Pixels.ToArray().Count(pixel => pixel != 0));
    }

    [Fact]
    public void PointerSceneRestorationAndTranslatedPreservationUsePointerFreePixels()
    {
        var output = new ArrayFramebufferPresenter(8, 8); var canvas = new CpuFramebufferCanvas(output);
        canvas.Fill(0x336699, 0, 0, 8, 8); canvas.SaveScene();
        canvas.Fill(0xFFFFFF, 1, 1, 2, 2);
        canvas.BeginScene(new(0, 0, 8, 8)); canvas.RestoreSceneRegion(new(1, 1, 2, 2));
        canvas.PreserveTranslatedSceneRegion(new(1, 1, 2, 2), 4, 4);
        canvas.Fill(0x112233, 0, 0, 8, 8); canvas.EndScenePreservation(); canvas.Present();
        Assert.Equal(0x336699, output.Pixels.Span[4 * 8 + 4]);
        Assert.Equal(0x112233, output.Pixels.Span[1 * 8 + 1]);
    }

    [Fact]
    public void FingerprintDescribesSuccessfulPresentationRatherThanPendingCpuWrites()
    {
        var output = new ArrayFramebufferPresenter(8, 8); var canvas = new CpuFramebufferCanvas(output, timestamp: () => 42);
        Assert.False(canvas.TryFingerprintPresentedPixels(new(0, 0, 8, 8), out _));
        canvas.Fill(0x112233, 0, 0, 8, 8); canvas.Present();
        Assert.True(canvas.TryFingerprintPresentedPixels(new(0, 0, 8, 8), out var first));
        canvas.Fill(0xFFFFFF, 0, 0, 8, 8);
        Assert.True(canvas.TryFingerprintPresentedPixels(new(0, 0, 8, 8), out var pending));
        Assert.Equal(first, pending); Assert.Equal(42, canvas.LastPresentTicks);
        canvas.Present(new(0, 0, 1, 1));
        Assert.True(canvas.TryFingerprintPresentedPixels(new(0, 0, 8, 8), out var second));
        Assert.NotEqual(first.Fingerprint, second.Fingerprint); Assert.Equal(2, second.PresentationSequence);
    }

    [Fact]
    public void ActualCachedWebPixelsFollowAMovedViewportAndDoNotCacheOccludedPixels()
    {
        var output = new ArrayFramebufferPresenter(10, 10); var canvas = new CpuFramebufferCanvas(output);
        canvas.Fill(0xFFFFFF, 1, 1, 4, 4); canvas.StoreWebFrame(1, 2, 3, new(1, 1, 4, 4), 0, 0);
        canvas.Fill(0, 0, 0, 10, 10);
        Assert.True(canvas.TryRestoreWebFrame(1, 2, 3, new(5, 5, 4, 4), 0, 0)); canvas.Present();
        Assert.Equal(0xFFFFFF, output.Pixels.Span[5 * 10 + 5]); Assert.Equal(0, output.Pixels.Span[1 * 10 + 1]);
        canvas.SaveScene(); canvas.PreserveTranslatedSceneRegion(new(5, 5, 4, 4), 5, 5);
        canvas.StoreWebFrame(2, 2, 3, new(5, 5, 4, 4), 0, 0); canvas.EndScenePreservation();
        Assert.False(canvas.TryRestoreWebFrame(2, 2, 3, new(0, 0, 4, 4), 0, 0));
    }
}