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.Text.Json;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Rendering;
using static Vortice.Direct3D11.D3D11;

const int width=1600,height=900;
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.B8G8R8A8_UNorm,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-grid-shader-validation");Directory.CreateDirectory(output);var reports=new List<object>();
var lines=new GalaxyOriginalGridLine[GalaxyOriginalGrid.MaximumLines];
foreach(var (name,focus,yaw,pitch,scale) in new[]{("sol",new XFEEDToolBox.Core.Models.Coordinates(0,0,0),-.3,.45,4d),
    ("core",new XFEEDToolBox.Core.Models.Coordinates(25,-20,25900),-.3,.45,.5),
    ("far",new XFEEDToolBox.Core.Models.Coordinates(0,0,0),-.3,.9,.03)})
{
    context.ClearRenderTargetView(target,new Color4(.011f,.014f,.019f,1));
    var camera=GalaxyCamera.Create(focus,width,height,yaw,pitch,scale);
    var count=GalaxyOriginalGrid.Write(lines,focus,camera.Distance);renderer.SetOriginalGrid(lines.AsSpan(0,count));renderer.Draw(camera);
    var bytes=Read();File.WriteAllBytes(Path.Combine(output,name+".bgra"),bytes);
    context.ClearRenderTargetView(target,new Color4(.011f,.014f,.019f,1));renderer.DrawOriginalDxbc(camera);
    var original=Read();File.WriteAllBytes(Path.Combine(output,name+"-original-dxbc.bgra"),original);
    var difference=0L;var changedPixels=0;
    for(var i=0;i<bytes.Length;i+=4)
    {
        var at=0;for(var channel=0;channel<3;channel++)at=Math.Max(at,Math.Abs(bytes[i+channel]-original[i+channel]));
        difference+=at;if(at>3)changedPixels++;
    }
    var meanDifference=difference/(double)(width*height);
    if(meanDifference>.5||changedPixels>width*height*.01)throw new InvalidOperationException($"Port diverged from actual original DXBC: mean{meanDifference},pixels{changedPixels}.");
    var changed=0;var maximum=0;var sum=0L;
    for(var i=0;i<bytes.Length;i+=4){var value=Math.Max(bytes[i],Math.Max(bytes[i+1],bytes[i+2]));if(value>6)changed++;maximum=Math.Max(maximum,value);sum+=value;}
    reports.Add(new{name,renderer.SubmittedOriginalGridLines,changed,maximum,mean=sum/(double)(width*height),camera.Distance,meanDifference,changedPixels,renderer.OriginalGridWorldWidthRestored,renderer.OriginalGridFullRestored});
    if(renderer.SubmittedOriginalGridLines!=198||changed<20)throw new InvalidOperationException("Original grid failed to draw its actual world lines.");
}
// A world half-width must cover more pixels when projected nearer, and zero
// width must be absent. This tests actual rasterized quads, not a CPU formula.
var near=GalaxyCamera.Create(new(0,0,0),width,height,0,0,20);
var far=GalaxyCamera.Create(new(0,0,0),width,height,0,0,5);
var fixture=new GalaxyOriginalGridLine(-15,0,0,15,0,0,50);
var nearRows=DrawWidth(near,fixture);var farRows=DrawWidth(far,fixture);
if(nearRows<=farRows||farRows<=0)throw new InvalidOperationException($"World width did not scale with projected depth: {nearRows}/{farRows}");
renderer.SetOriginalGrid([fixture with {WidthMultiplier=0}]);if(renderer.SubmittedOriginalGridLines!=0)throw new InvalidOperationException("Zero-width line was enlarged.");
reports.Add(new{worldHalfWidth=1,nearPixels=nearRows,farPixels=farRows,zeroWidthHidden=true});
// Constellations share the actual viewport line object and shader, but have
// their own style6 (.1ly half-width,2.5 repeats/ly) and group opacity.
renderer.SetOriginalGrid([]);
var constellationCamera=GalaxyCamera.Create(new(0,0,12),width,height,0,0,40);
var constellation=new GalaxyResolvedConstellation("fixture",[new("from","to",new(-1,0,12),new(1,0,12))]);
renderer.SetOriginalConstellations([constellation],constellationCamera);
if(renderer.SubmittedOriginalConstellationLines!=1)throw new InvalidOperationException("Original constellation did not submit its complete visible group.");
context.ClearRenderTargetView(target,new Color4(0,0,0,1));renderer.Draw(constellationCamera);var constellationBytes=Read();
File.WriteAllBytes(Path.Combine(output,"constellation.bgra"),constellationBytes);
context.ClearRenderTargetView(target,new Color4(0,0,0,1));renderer.DrawOriginalDxbc(constellationCamera,true);var constellationOriginal=Read();
File.WriteAllBytes(Path.Combine(output,"constellation-original-dxbc.bgra"),constellationOriginal);
var constellationDifference=0L;var constellationChanged=0;var constellationRows=0;
for(var i=0;i<constellationBytes.Length;i+=4)
{
    var delta=0;for(var channel=0;channel<3;channel++)delta=Math.Max(delta,Math.Abs(constellationBytes[i+channel]-constellationOriginal[i+channel]));
    constellationDifference+=delta;if(delta>3)constellationChanged++;
}
for(var y=0;y<height;y++)if(constellationBytes[(y*width+width/2)*4]>0)constellationRows++;
var constellationMean=constellationDifference/(double)(width*height);
if(constellationMean>.5||constellationChanged>width*height*.01||constellationRows<4)
    throw new InvalidOperationException("Original constellation world-style shader failed controlled DXBC comparison.");
renderer.SetOriginalConstellations([],constellationCamera);
context.ClearRenderTargetView(target,new Color4(0,0,0,1));renderer.Draw(constellationCamera);var hidden=Read();
if(renderer.SubmittedOriginalConstellationLines!=0||Enumerable.Range(0,width*height).Any(i=>hidden[i*4]!=0||hidden[i*4+1]!=0||hidden[i*4+2]!=0))
    throw new InvalidOperationException("Disabled constellation left a world-line buffer visible.");
reports.Add(new{constellation=true,sourceStyle=6,GalaxyOriginalConstellations.WorldHalfWidth,GalaxyOriginalConstellations.TextureRepeatPerLightYear,
    renderedRows=constellationRows,meanDifference=constellationMean,changedPixels=constellationChanged,disabledClear=true,renderer.OriginalConstellationWorldStyleRestored});
// Inspect floating source storage independently of the final tone mapper.
// This specifically catches scaling alpha along with RGB or retaining the
// old premultiplied/source-over adapter on only one of the two shader paths.
using(var floatTexture=device.CreateTexture2D(Format.R32G32B32A32_Float,width,height,mipLevels:1,bindFlags:BindFlags.RenderTarget))
using(var floatTarget=device.CreateRenderTargetView(floatTexture))
{
    renderer.SetOriginalGrid([fixture]);context.OMSetRenderTargets(floatTarget);
    context.ClearRenderTargetView(floatTarget,new Color4(0,0,0,0));renderer.Draw(near,1);var unscaled=ReadFloat(floatTexture);
    var write=XFEEDToolBox.Core.Rendering.GalaxyOriginalHdr.WriteScale;
    context.ClearRenderTargetView(floatTarget,new Color4(0,0,0,0));renderer.Draw(near,write);var storage=ReadFloat(floatTexture);
    context.ClearRenderTargetView(floatTarget,new Color4(0,0,0,0));renderer.DrawOriginalDxbc(near,false,write);var originalStorage=ReadFloat(floatTexture);
    var rgbError=0f;var alphaError=0f;var originalError=0f;var visible=0;
    for(var i=0;i<storage.Length;i++)
    {
        if(i%4==3)alphaError=Math.Max(alphaError,Math.Abs(storage[i]-unscaled[i]));
        else rgbError=Math.Max(rgbError,Math.Abs(storage[i]-unscaled[i]*write));
        originalError=Math.Max(originalError,Math.Abs(storage[i]-originalStorage[i]));
        if(i%4!=3&&storage[i]>0)visible++;
    }
    if(rgbError>1e-5||alphaError>1e-5||originalError>.005||visible==0)throw new InvalidOperationException("Original grid HDR Write changed source alpha or diverged from actual DXBC.");
    reports.Add(new{hdrStorage=true,hdrWrite=write,rgbError,alphaError,maximumOriginalFloatDifference=originalError,visibleChannels=visible,
        originalBlend="SourceAlpha/One/Add",sdrPremultiplicationAdapterApplied=false,finalToneMapTested=false});
    context.OMSetRenderTargets(target);
}
File.WriteAllText(Path.Combine(output,"report.json"),JsonSerializer.Serialize(reports,new JsonSerializerOptions{WriteIndented=true}));Console.WriteLine(JsonSerializer.Serialize(reports));

int DrawWidth(GalaxyCamera camera,GalaxyOriginalGridLine fixture)
{
    context.ClearRenderTargetView(target,new Color4(0,0,0,1));renderer.SetOriginalGrid([fixture]);renderer.Draw(camera);var bytes=Read();var rows=0;
    for(var y=0;y<height;y++){var offset=(y*width+width/2)*4;if(bytes[offset]>0)rows++;}
    return rows;
}
byte[] Read()
{
    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 bytes=new byte[width*height*4];
    for(var y=0;y<height;y++)Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),bytes,y*width*4,width*4);context.Unmap(staging,0);return bytes;
}
float[] ReadFloat(ID3D11Texture2D texture)
{
    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];
    try{for(var y=0;y<height;y++)Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),values,y*width*4,width*4);}
    finally{context.Unmap(staging,0);}return values;
}

namespace XFEEDToolBox.Rendering
{
    internal sealed partial class GalaxyGraphics:IDisposable
    {
        private readonly ID3D11Device device;private readonly ID3D11DeviceContext context;private readonly ID3D11SamplerState sampler;private readonly ID3D11BlendState additive;
        internal int DrawCalls;
        private readonly ID3D11VertexShader originalVs;
        private readonly ID3D11PixelShader originalPs;
        private readonly ID3D11InputLayout originalLayout;
        private readonly ID3D11Buffer originalMesh,originalB0,originalB1,originalB2;
        private readonly ID3D11BlendState originalBlend;
        internal GalaxyGraphics(ID3D11Device d,ID3D11DeviceContext c)
        {
            device=d;context=c;sampler=d.CreateSamplerState(new SamplerDescription(Filter.MinMagMipLinear,TextureAddressMode.Clamp,TextureAddressMode.Clamp,TextureAddressMode.Clamp));additive=d.CreateBlendState(new BlendDescription(Blend.One,Blend.InverseSourceAlpha));InitializeOriginalGrid(Path.GetFullPath("XFEEDToolBox/Assets/GalaxyMap.hlsl"));
            var folder="artifacts/galaxy-query-research/power-outer-sources/effects/";
            var vs=File.ReadAllBytes(folder+"vs_StarMapLine_Forward0_0_Win64_SM50.dxbc");originalVs=d.CreateVertexShader(vs);originalPs=d.CreatePixelShader(File.ReadAllBytes(folder+"ps_StarMapLine_Forward0_0_Win64_SM50.dxbc"));
            originalLayout=d.CreateInputLayout([
                new InputElementDescription("TEXCOORD",0,Format.R16G16B16A16_Float,0,1),new InputElementDescription("TEXCOORD",1,Format.R32_Float,8,1),
                new InputElementDescription("POSITION",0,Format.R32G32B32_Float,0,0,InputClassification.PerInstanceData,1),new InputElementDescription("POSITION",1,Format.R32G32B32_Float,12,0,InputClassification.PerInstanceData,1),
                new InputElementDescription("TEXCOORD",3,Format.R16G16B16A16_Float,24,0,InputClassification.PerInstanceData,1),new InputElementDescription("POSITION",4,Format.R32G32B32A32_Float,32,0,InputClassification.PerInstanceData,1),
                new InputElementDescription("TEXCOORD",5,Format.R32G32B32A32_Float,48,0,InputClassification.PerInstanceData,1)],vs);
            originalMesh=d.CreateBuffer(72,BindFlags.VertexBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
            Upload<OriginalQuad>(originalMesh,[new(0f,1f,-1f,-1f,1),new(0f,0f,-1f,1f,1),new(1f,0f,1f,1f,2),new(1f,0f,1f,1f,2),new(1f,1f,1f,-1f,2),new(0f,1f,-1f,-1f,1)]);
            originalB0=d.CreateBuffer(128,BindFlags.ConstantBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);originalB1=d.CreateBuffer(280*16,BindFlags.ConstantBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);originalB2=d.CreateBuffer(16,BindFlags.ConstantBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
            // Actual effect copybank state, not the former controlled SDR
            // source-over adapter. Both shaders use SrcAlpha/One/Add.
            originalBlend=d.CreateBlendState(new BlendDescription(Blend.SourceAlpha,Blend.One));
        }
        internal void Draw(GalaxyCamera camera,float hdrWrite=1){context.OMSetBlendState(additive);DrawOriginalGrid(camera,hdrWrite);}
        internal void DrawOriginalDxbc(GalaxyCamera camera,bool constellation=false,float hdrWrite=1)
        {
            var eye=new Vector3((float)(camera.Eye.X+49985),(float)(camera.Eye.Y+40985),(float)(camera.Eye.Z+24105));
            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);
            Vector4[] projection=[default,default,default,default,new(x,-Vector3.Dot(x,eye)),new(y,-Vector3.Dot(y,eye)),new(0,0,0,(float)camera.Near),new(forward,-Vector3.Dot(forward,eye))];
            var globals=new Vector4[280];globals[90]=new(0,hdrWrite,0,0);globals[275]=new(eye,0);
            Upload<Vector4>(originalB0,projection);Upload<Vector4>(originalB1,globals);Upload<Vector4>(originalB2,[XFEEDToolBox.Core.Rendering.GalaxyOriginalGridTexture.Reference.AuthoredFade]);
            context.OMSetBlendState(originalBlend);context.VSSetConstantBuffer(0,originalB0);context.VSSetConstantBuffer(1,originalB1);context.PSSetConstantBuffer(1,originalB1);context.PSSetConstantBuffer(2,originalB2);
            context.IASetInputLayout(originalLayout);context.IASetVertexBuffer(0,constellation?originalConstellationBuffer:originalGridBuffer,64);context.IASetVertexBuffer(1,originalMesh,12);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
            context.VSSetShader(originalVs);context.PSSetShader(originalPs);context.PSSetShaderResource(0,originalGridView);context.PSSetSampler(0,originalGridSampler);context.DrawInstanced(6,(uint)(constellation?originalConstellationCount:originalGridCount),0,0);context.PSSetShaderResource(0,null!);
        }
        private unsafe void Upload<T>(ID3D11Buffer buffer,ReadOnlySpan<T> data) where T:unmanaged
        {var mapped=context.Map(buffer,0,MapMode.WriteDiscard);try{MemoryMarshal.AsBytes(data).CopyTo(new Span<byte>((void*)mapped.DataPointer,data.Length*Marshal.SizeOf<T>()));}finally{context.Unmap(buffer,0);}}
        public void Dispose(){DisposeOriginalGrid();sampler.Dispose();additive.Dispose();originalVs.Dispose();originalPs.Dispose();originalLayout.Dispose();originalMesh.Dispose();originalB0.Dispose();originalB1.Dispose();originalB2.Dispose();originalBlend.Dispose();}
        [StructLayout(LayoutKind.Sequential)] private readonly record struct OriginalQuad(Half U,Half V,Half X,Half Y,float Endpoint)
        {internal OriginalQuad(float u,float v,float x,float y,float endpoint):this((Half)u,(Half)v,(Half)x,(Half)y,endpoint){}}
    }
}