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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Numerics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text.Json;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Rendering;
using XFEEDToolBox.Rendering;
using static Vortice.Direct3D11.D3D11;

const int width=640,height=360;
D3D11CreateDevice(IntPtr.Zero,DriverType.Warp,DeviceCreationFlags.BgraSupport,[FeatureLevel.Level_11_0],out var device,out _,out var context).CheckError();
using var d=device;using var c=context;using var renderer=new GalaxyGraphics(device,context);
using var texture=device.CreateTexture2D(Format.R32G32B32A32_Float,width,height,mipLevels:1,bindFlags:BindFlags.RenderTarget);
using var target=device.CreateRenderTargetView(texture);
using var rasterizer=device.CreateRasterizerState(new RasterizerDescription(CullMode.None,FillMode.Solid));
using var noDepth=device.CreateDepthStencilState(new DepthStencilDescription(false,DepthWriteMask.Zero,ComparisonFunction.Always));
context.OMSetRenderTargets(target);context.RSSetViewport(new Viewport(width,height));context.RSSetState(rasterizer);context.OMSetDepthStencilState(noDepth);
var output=Path.GetFullPath("artifacts/galaxy-core-shader-validation");Directory.CreateDirectory(output);var reports=new List<object>();
foreach(var (name,focus,yaw,pitch,scale) in new[]{("sol",new XFEEDToolBox.Core.Models.Coordinates(0,0,0),-.3,.45,4d),
    ("centre",new XFEEDToolBox.Core.Models.Coordinates(15,-30,25895),-.3,.45,.5),
    ("above",new XFEEDToolBox.Core.Models.Coordinates(15,20000,25895),-.3,.7,.05)})
{
    var camera=GalaxyCamera.Create(focus,width,height,yaw,pitch,scale);
    context.ClearRenderTargetView(target,new Color4(0,0,0,0));renderer.Draw(camera);var actual=Read();
    context.ClearRenderTargetView(target,new Color4(0,0,0,0));renderer.DrawOriginalDxbc(camera);var original=Read();
    var maximum=0f;double sum=0,brightness=0;var nonfinite=0;var significant=0;
    for(var i=0;i<actual.Length;i++)
    {
        if(!float.IsFinite(actual[i])||!float.IsFinite(original[i])){nonfinite++;continue;}
        var difference=Math.Abs(actual[i]-original[i]);maximum=Math.Max(maximum,difference);sum+=difference;
        if(difference>.005f)significant++;
        if(i%4<3)brightness+=actual[i];
    }
    if(nonfinite>0||sum/actual.Length>.001||significant>actual.Length*.001)
        throw new InvalidOperationException($"Original Core DXBC difference{name}: max{maximum},mean{sum/actual.Length},sig{significant},nonfinite{nonfinite}");
    var bgra=new byte[width*height*4];for(var i=0;i<actual.Length;i+=4){bgra[i]=(byte)(Math.Clamp(actual[i+2],0,1)*255);bgra[i+1]=(byte)(Math.Clamp(actual[i+1],0,1)*255);bgra[i+2]=(byte)(Math.Clamp(actual[i],0,1)*255);bgra[i+3]=255;}
    File.WriteAllBytes(Path.Combine(output,name+".bgra"),bgra);
    reports.Add(new{name,width,height,maximumDifference=maximum,meanDifference=sum/actual.Length,significantValues=significant,
        nonfinite,meanRgb=brightness/(width*height*3),renderer.OriginalCoreReady,renderer.OriginalCoreFullRestored,
        actualOriginalVsAndPsCompared=true,controlledSharedRgbMultiplier=1,controlledSharedEmissiveScale=1});
}
File.WriteAllText(Path.Combine(output,"report.json"),JsonSerializer.Serialize(reports,new JsonSerializerOptions{WriteIndented=true}));Console.WriteLine(JsonSerializer.Serialize(reports));
float[] Read()
{
    context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());var desc=texture.Description;desc.BindFlags=BindFlags.None;desc.CPUAccessFlags=CpuAccessFlags.Read;desc.Usage=ResourceUsage.Staging;
    using var staging=device.CreateTexture2D(desc);context.CopyResource(staging,texture);var mapped=context.Map(staging,0,MapMode.Read);var values=new float[width*height*4];
    for(var y=0;y<height;y++)Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),values,y*width*4,width*4);context.Unmap(staging,0);context.OMSetRenderTargets(target);return values;
}

namespace XFEEDToolBox.Rendering
{
    internal sealed partial class GalaxyGraphics:IDisposable
    {
        private readonly ID3D11Device device;private readonly ID3D11DeviceContext context;private readonly ID3D11BlendState additive;
        internal int DrawCalls;
        private readonly ID3D11VertexShader sourceVs;private readonly ID3D11PixelShader sourcePs;
        private readonly ID3D11InputLayout sourceLayout;private readonly ID3D11Buffer sourceMesh,sourceB0,sourceB1,sourceB2;
        internal GalaxyGraphics(ID3D11Device d,ID3D11DeviceContext c)
        {
            device=d;context=c;additive=d.CreateBlendState(new BlendDescription(Blend.One,Blend.One));
            InitializeOriginalCore(Path.GetFullPath("XFEEDToolBox/Assets/GalaxyCore.hlsl"));
            var folder="artifacts/galaxy-query-research/power-outer-sources/authored-models/";
            var vs=File.ReadAllBytes(folder+"effects/vs_GalaxyGlow_Forward0_0_0_Win64_SM50.dxbc");
            var ps=File.ReadAllBytes(folder+"effects/ps_GalaxyGlow_Forward0_0_0_Win64_SM50.dxbc");
            if(Convert.ToHexStringLower(SHA256.HashData(vs))!="6670cd39f72f471399a2563c03c27c89035d612ac1cd1c431234ec38e9678de8"||
               Convert.ToHexStringLower(SHA256.HashData(ps))!="d8846f3b7cb1fb4581e0bbbb2e00b0e5a4180f40289cc5fb62734fcb198db270")throw new InvalidDataException("Original Core DXBC changed");
            sourceVs=d.CreateVertexShader(vs);sourcePs=d.CreatePixelShader(ps);
            sourceLayout=d.CreateInputLayout([new InputElementDescription("PACKEDVERTEXDATAA",0,Format.R32G32B32A32_UInt,0,0)],vs);
            var bytes=File.ReadAllBytes(folder+"milkywaycore_.gpu");sourceMesh=d.CreateBuffer<byte>(bytes.AsSpan(1176),BindFlags.VertexBuffer);
            sourceB0=d.CreateBuffer(12*16,BindFlags.ConstantBuffer);sourceB1=d.CreateBuffer(276*16,BindFlags.ConstantBuffer);
            sourceB2=d.CreateBuffer<Vector4>(GalaxyOriginalCore.Reference.MaterialConstants.ToArray(),BindFlags.ConstantBuffer);
        }
        internal void Draw(GalaxyCamera camera)=>DrawOriginalCore(camera,true);
        internal void DrawOriginalDxbc(GalaxyCamera camera)
        {
            var eye=new Vector3((float)(camera.Eye.X+49985),(float)(camera.Eye.Y+40985),(float)(camera.Eye.Z+24105));
            var delta=GalaxyOriginalCoreResources.WorldCentre-eye;var scale=GalaxyOriginalCoreResources.WorldScale;
            var right=new Vector3((float)camera.Right.X,(float)camera.Right.Y,(float)camera.Right.Z);
            var up=new Vector3((float)camera.Up.X,(float)camera.Up.Y,(float)camera.Up.Z);
            var forward=new Vector3((float)camera.Forward.X,(float)camera.Forward.Y,(float)camera.Forward.Z);
            var x=right*(float)(camera.FocalLength*2/camera.Width);var y=up*(float)(camera.FocalLength*2/camera.Height);
            var rows=new Vector4[12];rows[4]=new(x*scale,Vector3.Dot(delta,x));rows[5]=new(y*scale,Vector3.Dot(delta,y));
            rows[6]=new(0,0,0,(float)camera.Near);rows[7]=new(forward*scale,Vector3.Dot(delta,forward));
            rows[9]=new(scale,0,0,delta.X);rows[10]=new(0,scale,0,delta.Y);rows[11]=new(0,0,scale,delta.Z);
            context.UpdateSubresource<Vector4>(rows,sourceB0);var shared=new Vector4[276];shared[90]=new(0,1,1,0);shared[275]=new(eye,0);context.UpdateSubresource<Vector4>(shared,sourceB1);
            context.VSSetConstantBuffer(0,sourceB0);context.PSSetConstantBuffer(1,sourceB1);context.PSSetConstantBuffer(2,sourceB2);
            context.IASetInputLayout(sourceLayout);context.IASetVertexBuffer(0,sourceMesh,40);context.IASetIndexBuffer(originalCoreIndices,Format.R16_UInt,0);
            context.VSSetShader(sourceVs);context.PSSetShader(sourcePs);context.PSSetShaderResource(0,originalCoreView);context.PSSetSampler(0,originalCoreSampler);
            context.OMSetBlendState(originalCoreBlend);context.DrawIndexed(576,0,0);context.PSSetShaderResource(0,null!);
        }
        public void Dispose()
        {
            DisposeOriginalCore();sourceVs.Dispose();sourcePs.Dispose();sourceLayout.Dispose();sourceMesh.Dispose();sourceB0.Dispose();sourceB1.Dispose();sourceB2.Dispose();additive.Dispose();
        }
    }
}