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(); 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;i3)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;i6)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;i3)constellationChanged++; } for(var y=0;y0)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;i0)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;y0)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(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(originalB0,projection);Upload(originalB1,globals);Upload(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(ID3D11Buffer buffer,ReadOnlySpan data) where T:unmanaged {var mapped=context.Map(buffer,0,MapMode.WriteDiscard);try{MemoryMarshal.AsBytes(data).CopyTo(new Span((void*)mapped.DataPointer,data.Length*Marshal.SizeOf()));}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){}} } }