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.D3DCompiler;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using XFEEDToolBox.Core.Rendering;
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 source=new GalaxyGraphics(device);
using var texture=device.CreateTexture2D(Format.B8G8R8A8_UNorm,width,height,mipLevels:1,bindFlags:BindFlags.RenderTarget);
using var target=device.CreateRenderTargetView(texture);using var blend=device.CreateBlendState(new BlendDescription(Blend.SourceAlpha,Blend.One));
using var rasterizer=device.CreateRasterizerState(new RasterizerDescription(CullMode.None,FillMode.Solid));
using var noDepth=device.CreateDepthStencilState(new DepthStencilDescription(false,DepthWriteMask.Zero,ComparisonFunction.Always));
using var sampler=device.CreateSamplerState(new SamplerDescription(Filter.MinMagMipLinear,TextureAddressMode.Clamp,TextureAddressMode.Clamp,TextureAddressMode.Clamp));
using var constants=device.CreateBuffer(80,BindFlags.ConstantBuffer);
using var outputConstants=device.CreateBuffer<Vector4>([new(1,1,0,0)],BindFlags.ConstantBuffer);
context.PSSetConstantBuffer(8,outputConstants);
var shader=Path.GetFullPath("XFEEDToolBox/Assets/GalaxyMap.hlsl");
foreach(var entry in new[]{"VSStar","VSLine","VSSky","VSOverview","VSNebula","VSPowerContour","VSMilkyWay","PSMilkyWay","VSOriginalGrid","PSOriginalGrid","PSStar","PSLine","PSSky","PSInspectSky","PSOverview","PSGalacticZones","PSPowerContour","PSNebula","PSNebulaComposite"})
    Compiler.CompileFromFile(shader,entry,entry.StartsWith("VS",StringComparison.Ordinal)?"vs_5_0":"ps_5_0");
var vs=Compiler.CompileFromFile(shader,"VSStar","vs_5_0");
using var vertex=device.CreateVertexShader(vs.Span);using var pixel=device.CreatePixelShader(Compiler.CompileFromFile(shader,"PSStar","ps_5_0").Span);
using var layout=device.CreateInputLayout([
    new InputElementDescription("POSITION",0,Format.R32G32_Float,0,0,InputClassification.PerInstanceData,1),
    new InputElementDescription("RADIUS",0,Format.R32G32_Float,8,0,InputClassification.PerInstanceData,1),
    new InputElementDescription("COLOR",0,Format.R32G32B32A32_Float,16,0,InputClassification.PerInstanceData,1),
    new InputElementDescription("APPEARANCE",0,Format.R32G32B32A32_Float,32,0,InputClassification.PerInstanceData,1)],vs.Span);
List<Sprite> stars=[];
for(var layer=11;layer<28;layer++)for(var row=0;row<4;row++)
{
    var radius=new[]{2f,4f,8f,16f}[row];var x=60+(layer-11)*88;var y=160+row*180;
    var colour=row switch{0=>new Vector4(1,.5f,.1f,1),1=>new Vector4(.34f,.59f,.98f,1),2=>new Vector4(.22f,.7f,.28f,1),_=>new Vector4(.95f,.3f,.8f,.35f)};
    stars.Add(new(new(x,y),radius*4.1f,0,colour,new(radius*4,layer,0,0)));
}
using var buffer=device.CreateBuffer((uint)stars.Count*48,BindFlags.VertexBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
unsafe{var mapped=context.Map(buffer,0,MapMode.WriteDiscard);MemoryMarshal.AsBytes(CollectionsMarshal.AsSpan(stars)).CopyTo(new Span<byte>((void*)mapped.DataPointer,stars.Count*48));context.Unmap(buffer,0);}
var camera=new Camera(new(width,height,0,0),default,default,default,default);context.UpdateSubresource(in camera,constants);
context.OMSetRenderTargets(target);context.ClearRenderTargetView(target,new Color4(.011f,.014f,.019f,1));context.RSSetViewport(new Viewport(width,height));
context.RSSetState(rasterizer);context.OMSetDepthStencilState(noDepth);context.OMSetBlendState(blend);context.IASetInputLayout(layout);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
context.IASetVertexBuffer(0,buffer,48);context.VSSetShader(vertex);context.PSSetShader(pixel);context.VSSetConstantBuffer(0,constants);context.PSSetConstantBuffer(0,constants);
source.Bind(context);context.PSSetSampler(0,sampler);context.DrawInstanced(6,(uint)stars.Count,0,0);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 map=context.Map(staging,0,MapMode.Read);var bytes=new byte[width*height*4];
for(var y=0;y<height;y++)Marshal.Copy(map.DataPointer+(int)(y*map.RowPitch),bytes,y*width*4,width*4);context.Unmap(staging,0);
var output=Path.GetFullPath("artifacts/galaxy-stellar-shader-validation");Directory.CreateDirectory(output);File.WriteAllBytes(Path.Combine(output,"classified-sprites.bgra"),bytes);
// The real shader adds a radial internal glow to the flat source disc.
int Channel(int x,int y,int ch)=>bytes[(y*width+x)*4+ch];
var centre=Channel(236,520,1);var interior=Channel(239,520,1);var outside=Channel(246,520,1);
if(centre<240||interior<230||outside>5)throw new InvalidOperationException($"Original disc failed: {centre}/{interior}/{outside}");
var hdr=new[]{VerifyHdrMath(1),VerifyHdrMath(GalaxyOriginalHdr.WriteScale)};
var sourceData=GalaxyOriginalStarSprites.Reference;
var report=new{width,height,draws=1,instances=stars.Count,source=sourceData.SourceSha256,payload=sourceData.PayloadSha256,source.OriginalClassifiedSpritesReady,
    source.OriginalClassifiedShaderRestored,defaultDisc=new{centre,interior,outside},hdr,layers=Enumerable.Range(11,17).ToArray()};
File.WriteAllText(Path.Combine(output,"report.json"),JsonSerializer.Serialize(report,new JsonSerializerOptions{WriteIndented=true}));Console.WriteLine(JsonSerializer.Serialize(report));

object VerifyHdrMath(float hdrWrite)
{
    var outputValue=new Vector4(hdrWrite,1,0,0);context.UpdateSubresource(in outputValue,outputConstants);
    context.PSSetConstantBuffer(8,outputConstants);context.VSSetShader(vertex);context.PSSetShader(pixel);source.Bind(context);
    using var hdrTexture=device.CreateTexture2D(Format.R32G32B32A32_Float,512,160,mipLevels:1,bindFlags:BindFlags.RenderTarget);
    using var hdrTarget=device.CreateRenderTargetView(hdrTexture);
    var inputs=new[]{new Vector4(.25f,.5f,1.5f,1),new Vector4(.25f,.5f,1.5f,.35f),new Vector4(.25f,.5f,1.5f,0),new Vector4(100,2,.1f,1)};
    var samples=inputs.Select((colour,index)=>new Sprite(new(64+index*128,80),32,0,colour,new(32,13,index==1?2:0,0))).ToArray();
    unsafe{var mapped=context.Map(buffer,0,MapMode.WriteDiscard);MemoryMarshal.AsBytes(samples.AsSpan()).CopyTo(new Span<byte>((void*)mapped.DataPointer,samples.Length*48));context.Unmap(buffer,0);}
    var hdrCamera=new Camera(new(512,160,0,0),default,default,default,default);context.UpdateSubresource(in hdrCamera,constants);
    context.OMSetRenderTargets(hdrTarget);context.ClearRenderTargetView(hdrTarget,new Color4(0,0,0,0));context.RSSetViewport(new Viewport(512,160));
    // Inspect the production pixel output before the SDR compositor clamps it.
    context.OMSetBlendState(null);context.DrawInstanced(6,(uint)samples.Length,0,0);context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());
    var desc=hdrTexture.Description;desc.BindFlags=BindFlags.None;desc.CPUAccessFlags=CpuAccessFlags.Read;desc.Usage=ResourceUsage.Staging;
    using var staging=device.CreateTexture2D(desc);context.CopyResource(staging,hdrTexture);var mappedHdr=context.Map(staging,0,MapMode.Read);
    var actual=new Vector4[samples.Length];
    try{for(var index=0;index<samples.Length;index++)actual[index]=Marshal.PtrToStructure<Vector4>(mappedHdr.DataPointer+(int)(80*mappedHdr.RowPitch)+(64+index*128)*16);}
    finally{context.Unmap(staging,0);}
    // Layer13's white disc has all three source channels=1, and the actual
    // Galaxy producer sets both additional-channel weights=1.
    var gain=(2.75f-MathF.Sqrt(.5f)/(32*.17f)+1)*1.903f*MathF.Pow(3,1.2f);
    for(var index=0;index<samples.Length;index++)
    {
        var input=inputs[index];var gamma=index==1?1:2.2f;
        var expected=new Vector4(Math.Min(100,gain*MathF.Pow(input.X,gamma))*hdrWrite,
            Math.Min(100,gain*MathF.Pow(input.Y,gamma))*hdrWrite,Math.Min(100,gain*MathF.Pow(input.Z,gamma))*hdrWrite,input.W);
        if(Vector4.Distance(actual[index],expected)>.003f)throw new InvalidOperationException($"Original shader math{index}: {actual[index]}, expected {expected}");
    }
    if(actual[0].Z/hdrWrite<=1||actual[3].X/hdrWrite<99.9f)throw new InvalidOperationException("Original HDR input or clamp was lost.");
    // Use the actual original PS bytecode as an independent GPU oracle. The
    // bridge VS supplies its original semantics; it does not clone PS maths.
    const string bridge="""
        cbuffer Camera:register(b0){float4 viewport;}
        struct Input{float2 position:POSITION;float2 radiusKind:RADIUS;float4 colour:COLOR;float4 appearance:APPEARANCE;};
        // Match the original VS output register order exactly. Independently
        // compiled VS/PS stages do not relink by semantic names alone.
        struct Output{float4 worldSize:TEXCOORD0;float4 colour:TEXCOORD1;float3 centre:TEXCOORD2;float2 weights:TEXCOORD4;float3 uvLayer:TEXCOORD5;float4 position:SV_POSITION;};
        Output main(Input s,uint vertex:SV_VertexID){
            const float2 q[6]={float2(-1,-1),float2(-1,1),float2(1,-1),float2(1,-1),float2(-1,1),float2(1,1)};
            Output p;float2 offset=q[vertex]*s.radiusKind.x;float2 xy=s.position+offset;
            p.position=float4(xy.x/viewport.x*2-1,1-xy.y/viewport.y*2,0,1);
            p.worldSize=float4(offset,0,s.appearance.x);p.centre=0;
            p.colour=float4(pow(max(0,s.colour.rgb),s.appearance.z>1.5?1:2.2),s.colour.a);
            p.weights=1;p.uvLayer=float3(offset/(s.appearance.x*2)+.5,s.appearance.y);return p;
        }
        """;
    using var bridgeVertex=device.CreateVertexShader(Compiler.Compile(bridge,"main","original-star-bridge","vs_5_0").Span);
    var originalBytes=File.ReadAllBytes("artifacts/galaxy-query-research/power-outer-sources/effects/background-stars-ps.dxbc");
    if(Convert.ToHexStringLower(System.Security.Cryptography.SHA256.HashData(originalBytes))!="a9eef9ea89da95e7810933cdbf58b798e105378ab4f9187409b232ab8fe91d9c")throw new InvalidDataException("Pinned original PS changed");
    using var originalPixel=device.CreatePixelShader(originalBytes);
    var shared=new Vector4[91];shared[90]=new(0,hdrWrite,0,0);
    using var sharedBuffer=device.CreateBuffer<Vector4>(shared,BindFlags.ConstantBuffer);
    using var materialBuffer=device.CreateBuffer<Vector4>([new(2.2f,2.75f,.17f,1.903f)],BindFlags.ConstantBuffer);
    context.OMSetRenderTargets(hdrTarget);context.ClearRenderTargetView(hdrTarget,new Color4(0,0,0,0));
    context.VSSetShader(bridgeVertex);context.PSSetShader(originalPixel);context.PSSetConstantBuffer(1,sharedBuffer);context.PSSetConstantBuffer(2,materialBuffer);
    source.BindOriginal(context);context.DrawInstanced(6,(uint)samples.Length,0,0);context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());
    context.CopyResource(staging,hdrTexture);mappedHdr=context.Map(staging,0,MapMode.Read);
    var difference=0f;
    try
    {
        for(var index=0;index<samples.Length;index++)
        {
            var original=Marshal.PtrToStructure<Vector4>(mappedHdr.DataPointer+(int)(80*mappedHdr.RowPitch)+(64+index*128)*16);
            var expected=new Vector3(original.X,original.Y,original.Z);
            difference=Math.Max(difference,Vector3.Distance(new(actual[index].X,actual[index].Y,actual[index].Z),expected));
            if(Math.Abs(actual[index].W-original.W)>.00001f)throw new InvalidOperationException("Original source alpha was changed by HDR Write.");
        }
    }
    finally{context.Unmap(staging,0);}
    if(difference>.003f)throw new InvalidOperationException("Actual original PS GPU comparison failed: "+difference);
    Console.WriteLine("Actual original PS comparison RGB difference: "+difference);
    return new{samples=actual.Select(value=>new[]{value.X,value.Y,value.Z,value.W}).ToArray(),
        actualOriginalPixelShaderCompared=true,sampleCount=actual.Length,maximumRgbVectorDifference=difference,
        originalInternalGlow=new[]{2.75f,.17f,1.903f},hdrWrite,blend="SourceAlpha/One/Add",sourceAlphaUnchanged=true,sdrPremultiplicationAdapterApplied=false};
}

[StructLayout(LayoutKind.Sequential)] readonly record struct Sprite(Vector2 Position,float Radius,float Kind,Vector4 Colour,Vector4 Appearance);
[StructLayout(LayoutKind.Sequential)] readonly record struct Camera(Vector4 Viewport,Vector4 Options,Vector4 CentreScale,Vector4 PanOrigin,Vector4 DensityExtent);
namespace XFEEDToolBox.Rendering
{
    internal sealed partial class GalaxyGraphics:IDisposable
    {
        private readonly ID3D11Device device;
        internal GalaxyGraphics(ID3D11Device input){device=input;InitializeOriginalSprites();}
        internal void Bind(ID3D11DeviceContext context)=>context.PSSetShaderResource(7,originalSprites!);
        internal void BindOriginal(ID3D11DeviceContext context)=>context.PSSetShaderResource(0,originalSprites!);
        public void Dispose()=>DisposeOriginalSprites();
    }
}