using System.Numerics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text.Json;
using Vortice.D3DCompiler;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Rendering;
using static Vortice.Direct3D11.D3D11;
const int width=256,height=256;
var output=Path.GetFullPath("artifacts/galaxy-power-activity-billboard-probe");Directory.CreateDirectory(output);
void Require(bool condition,string message){if(!condition)throw new InvalidOperationException(message);}
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 texture=device.CreateTexture2D(Format.R32G32B32A32_Float,width,height,mipLevels:1,bindFlags:BindFlags.RenderTarget);
using var target=device.CreateRenderTargetView(texture);
using var staging=device.CreateTexture2D(new Texture2DDescription{Width=width,Height=height,Format=Format.R32G32B32A32_Float,ArraySize=1,MipLevels=1,
SampleDescription=new(1,0),Usage=ResourceUsage.Staging,CPUAccessFlags=CpuAccessFlags.Read});
using var blend=device.CreateBlendState(new BlendDescription(Blend.One,Blend.InverseSourceAlpha));
using var raster=device.CreateRasterizerState(new RasterizerDescription(CullMode.None,FillMode.Solid));
using var depth=device.CreateDepthStencilState(new DepthStencilDescription(false,DepthWriteMask.Zero,ComparisonFunction.Always));
var shader=Path.GetFullPath("XFEEDToolBox/Assets/GalaxyPowerActivityBillboard.hlsl");
var translatedVsCode=Compiler.CompileFromFile(shader,"VSOriginalPowerActivityBillboard","vs_5_0");
var translatedPsCode=Compiler.CompileFromFile(shader,"PSOriginalPowerActivityBillboard","ps_5_0");
var effects="artifacts/galaxy-query-research/power-outer-sources/effects";
var originalVsCode=File.ReadAllBytes(Path.Combine(effects,"vs_GalaxyMapFocusBillboard_Forward_0_Win64_SM50.dxbc"));
var originalPsCode=File.ReadAllBytes(Path.Combine(effects,"ps_GalaxyMapFocusBillboard_Forward_0_Win64_SM50.dxbc"));
using var translatedVs=device.CreateVertexShader(translatedVsCode.Span);using var translatedPs=device.CreatePixelShader(translatedPsCode.Span);
using var originalVs=device.CreateVertexShader(originalVsCode);using var originalPs=device.CreatePixelShader(originalPsCode);
InputElementDescription[] elements=[new("POSITION",0,Format.R32G32B32A32_Float,0,0,InputClassification.PerInstanceData,1),
new("UAXISEXTENT",0,Format.R32G32B32A32_Float,16,0,InputClassification.PerInstanceData,1),
new("VAXISEXTENT",0,Format.R32G32B32A32_Float,32,0,InputClassification.PerInstanceData,1),
new("USERDATA",0,Format.R32G32B32A32_Float,48,0,InputClassification.PerInstanceData,1)];
using var layout=device.CreateInputLayout(elements,translatedVsCode.Span);
// Deliberately wide synthetic billboard samples the PS over many pixels. It is
// only a shader fixture; it is never inserted into the game/source catalogue.
var instance=new GalaxyOriginalPowerActivityBillboard(new(0,0,0,1),new(1,0,0,20),new(0,0,1,20),new(2,1,.5f,0));
using var instances=device.CreateBuffer<GalaxyOriginalPowerActivityBillboard>(new[]{instance},BindFlags.VertexBuffer);
var camera=GalaxyCamera.Create(new(0,0,0),width,height,0,1.25,7);
var eye=camera.Eye;var right=camera.Right;var up=camera.Up;var forward=camera.Forward;
var original0=new Vector4[12];original0[9]=new((float)right.X,(float)right.Y,(float)right.Z,-(float)(right.X*eye.X+right.Y*eye.Y+right.Z*eye.Z));
original0[10]=new((float)up.X,(float)up.Y,(float)up.Z,-(float)(up.X*eye.X+up.Y*eye.Y+up.Z*eye.Z));
original0[11]=new((float)forward.X,(float)forward.Y,(float)forward.Z,-(float)(forward.X*eye.X+forward.Y*eye.Y+forward.Z*eye.Z));
var original1=new Vector4[333];original1[90]=new(0,1,0,0);original1[270]=new((float)(camera.FocalLength/(width*.5)),0,0,0);
original1[271]=new(0,(float)(camera.FocalLength/(height*.5)),0,0);original1[272]=new(0,0,0,1);original1[273]=new(0,0,(float)camera.Near,0);
original1[332]=new(width,height,0,0);
float Int(int value)=>BitConverter.Int32BitsToSingle(value);
Vector4[] original2=[new(Int(1),Int(2),1,Int(0)),new(-20,20,.9f,.75f),new(.92f,.175f,1.5f,.005f)];
using var cb0=device.CreateBuffer<Vector4>(original0,BindFlags.ConstantBuffer);using var cb1=device.CreateBuffer<Vector4>(original1,BindFlags.ConstantBuffer);
using var cb2=device.CreateBuffer<Vector4>(original2,BindFlags.ConstantBuffer);
var translated=new Frame(new((float)eye.X,(float)eye.Y,(float)eye.Z,(float)camera.FocalLength),
new((float)right.X,(float)right.Y,(float)right.Z,width),new((float)up.X,(float)up.Y,(float)up.Z,height),
new((float)forward.X,(float)forward.Y,(float)forward.Z,(float)camera.Near),new(.9f,.75f,.92f,.175f),new(1.5f,.005f,width,height),new(1,1,0,0));
using var cb11=device.CreateBuffer((uint)Marshal.SizeOf<Frame>(),BindFlags.ConstantBuffer);context.UpdateSubresource(in translated,cb11);
var exposure=new[]{new Vector4(8),new Vector4(8)};ID3D11Texture2D exposureTexture;
unsafe{fixed(Vector4* p=exposure)exposureTexture=device.CreateTexture2D(new Texture2DDescription{Width=2,Height=1,Format=Format.R32G32B32A32_Float,ArraySize=1,MipLevels=1,
SampleDescription=new(1,0),Usage=ResourceUsage.Immutable,BindFlags=BindFlags.ShaderResource},[new SubresourceData((nint)p,32,32)]);}
using var et=exposureTexture;using var exposureView=device.CreateShaderResourceView(et);
float[] Draw(bool source,int repeats=1,bool ownedExposure=false)
{
var selected=translated with{Output=new(1,1,ownedExposure?1:0,0)};context.UpdateSubresource(in selected,cb11);
context.OMSetRenderTargets(target);context.ClearRenderTargetView(target,new Color4(0,0,0,0));context.RSSetViewport(new Viewport(width,height));
context.RSSetState(raster);context.OMSetDepthStencilState(depth);context.OMSetBlendState(blend);context.IASetInputLayout(layout);
context.IASetPrimitiveTopology(PrimitiveTopology.TriangleStrip);context.IASetVertexBuffer(0,instances,64);
context.VSSetShader(source?originalVs:translatedVs);context.PSSetShader(source?originalPs:translatedPs);
context.VSSetConstantBuffer(0,cb0);context.VSSetConstantBuffer(1,cb1);context.VSSetConstantBuffer(2,cb2);
context.PSSetConstantBuffer(1,cb1);context.PSSetConstantBuffer(2,cb2);context.PSSetShaderResource(0,exposureView);
context.PSSetShaderResource(20,ownedExposure?exposureView:null!);
context.VSSetConstantBuffer(12,cb11);context.PSSetConstantBuffer(12,cb11);
for(var i=0;i<repeats;i++)context.DrawInstanced(4,1,0,0);
context.PSSetShaderResource(20,null!);
context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());context.CopyResource(staging,texture);
var mapped=context.Map(staging,0,MapMode.Read);var values=new float[width*height*4];
for(var row=0;row<height;row++)Marshal.Copy(mapped.DataPointer+(int)(row*mapped.RowPitch),values,row*width*4,width*4);
context.Unmap(staging,0);return values;
}
var source=Draw(true);var port=Draw(false);var doubled=Draw(false,2);var ownedPort=Draw(false,1,true);
Require(source.All(float.IsFinite)&&port.All(float.IsFinite),"Non-finite shader output");
var maximum=source.Zip(port,(a,b)=>Math.Abs(a-b)).Max();var mean=source.Zip(port,(a,b)=>Math.Abs(a-b)).Average();
var lit=source.Where((_,i)=>i%4==0).Count(v=>v>1e-6);Require(lit>100,"Original shader did not produce contour samples");
Require(maximum<.01&&mean<.0001,"Original/translated FocusBillboard shader mismatch: "+maximum+" / "+mean);
Require(port.Where((_,i)=>i%4==3).All(v=>v==0),"Original range alpha0 changed");
Require(port.Zip(doubled,(a,b)=>Math.Abs(b-2*a)).Max()<1e-6,"Original additive blend changed");
Require(source.Zip(ownedPort,(a,b)=>Math.Abs(a-b)).Max()<.01,"Owned exposure texture did not match original texel1/type2 sampling");
XFEEDToolBox.Rendering.GalaxyGraphics.ValidateBillboardProduction(device,context,shader,camera,instance,target,texture,staging);
var report=new{passed=true,gameAccess=false,sourceDxbcGpuCompared=true,primitive="TriangleStrip",vertexCount=4,litPixels=lit,maximumError=maximum,meanError=mean,
explicitSyntheticEmissiveRescaling=1,originalRuntimeEmissiveResolved=false,productionUnknownSourceMustRemainHidden=true,
productionPartialSourceLinked=true,productionUnknownGateTested=true,productionOwnedManualExposureTested=true,sourceExtentNotRadius=true,
shaderSha256=Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(shader))),originalVsSha256=Convert.ToHexStringLower(SHA256.HashData(originalVsCode)),
originalPsSha256=Convert.ToHexStringLower(SHA256.HashData(originalPsCode))};
File.WriteAllText(Path.Combine(output,"result.json"),JsonSerializer.Serialize(report,new JsonSerializerOptions{WriteIndented=true}));Console.WriteLine(JsonSerializer.Serialize(report));
[StructLayout(LayoutKind.Sequential)] readonly record struct Frame(Vector4 EyeFocal,Vector4 RightWidth,Vector4 UpHeight,Vector4 ForwardNear,Vector4 Material,Vector4 Highlight,Vector4 Output);
namespace XFEEDToolBox.Rendering
{
internal sealed partial class GalaxyGraphics
{
private ID3D11Device device=null!;private ID3D11DeviceContext context=null!;private int width=256,height=256,DrawCalls;
private void Upload<T>(ID3D11Buffer buffer,ReadOnlySpan<T> values)where T:unmanaged
{var mapped=context.Map(buffer,0,MapMode.WriteDiscard);unsafe{values.CopyTo(new Span<T>((void*)mapped.DataPointer,values.Length));}context.Unmap(buffer,0);}
internal static void ValidateBillboardProduction(ID3D11Device device,ID3D11DeviceContext context,string shader,GalaxyCamera camera,GalaxyOriginalPowerActivityBillboard value,
ID3D11RenderTargetView target,ID3D11Texture2D texture,ID3D11Texture2D staging)
{
var graphics=new GalaxyGraphics{device=device,context=context};graphics.InitializeOriginalPowerActivityBillboard(shader);
try
{
graphics.SetOriginalPowerActivityBillboard(value);graphics.DrawOriginalPowerActivityBillboard(camera,1);
if(!graphics.PowerActivityBillboardSourceUnknown||graphics.SubmittedPowerActivityBillboards!=0)throw new InvalidOperationException("Unknown exposure source produced contour");
graphics.InitializeOriginalExposure(shader);graphics.DrawOriginalPowerActivityBillboard(camera,1);
if(graphics.SubmittedPowerActivityBillboards!=0)throw new InvalidOperationException("Zero default was made visible");
graphics.ComputeOriginalManualExposure();context.OMSetRenderTargets(target);context.ClearRenderTargetView(target,new Color4(0,0,0,0));
graphics.DrawOriginalPowerActivityBillboard(camera,1);
if(graphics.PowerActivityBillboardSourceUnknown||graphics.SubmittedPowerActivityBillboards!=1)throw new InvalidOperationException("Owned manual exposure did not reach billboard");
context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());context.CopyResource(staging,texture);
var mapped=context.Map(staging,0,MapMode.Read);var row=new float[256*4];var lit=0;
for(var y=0;y<256;y++){Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),row,0,row.Length);for(var x=0;x<row.Length;x+=4)if(float.IsFinite(row[x])&&row[x]>1e-6)lit++;}
context.Unmap(staging,0);if(lit<100)throw new InvalidOperationException("Production contour had no pixels");
graphics.SetOriginalPowerActivityBillboard(null);graphics.DrawOriginalPowerActivityBillboard(camera,1);
if(graphics.SubmittedPowerActivityBillboards!=0)throw new InvalidOperationException("Missing bound rendered contour");
}
finally{graphics.DisposeOriginalExposure();graphics.DisposeOriginalPowerActivityBillboard();}
}
}
}
using System.Numerics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text.Json;
using Vortice.D3DCompiler;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Rendering;
using static Vortice.Direct3D11.D3D11;
const int width=256,height=256;
var output=Path.GetFullPath("artifacts/galaxy-power-activity-billboard-probe");Directory.CreateDirectory(output);
void Require(bool condition,string message){if(!condition)throw new InvalidOperationException(message);}
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 texture=device.CreateTexture2D(Format.R32G32B32A32_Float,width,height,mipLevels:1,bindFlags:BindFlags.RenderTarget);
using var target=device.CreateRenderTargetView(texture);
using var staging=device.CreateTexture2D(new Texture2DDescription{Width=width,Height=height,Format=Format.R32G32B32A32_Float,ArraySize=1,MipLevels=1,
SampleDescription=new(1,0),Usage=ResourceUsage.Staging,CPUAccessFlags=CpuAccessFlags.Read});
using var blend=device.CreateBlendState(new BlendDescription(Blend.One,Blend.InverseSourceAlpha));
using var raster=device.CreateRasterizerState(new RasterizerDescription(CullMode.None,FillMode.Solid));
using var depth=device.CreateDepthStencilState(new DepthStencilDescription(false,DepthWriteMask.Zero,ComparisonFunction.Always));
var shader=Path.GetFullPath("XFEEDToolBox/Assets/GalaxyPowerActivityBillboard.hlsl");
var translatedVsCode=Compiler.CompileFromFile(shader,"VSOriginalPowerActivityBillboard","vs_5_0");
var translatedPsCode=Compiler.CompileFromFile(shader,"PSOriginalPowerActivityBillboard","ps_5_0");
var effects="artifacts/galaxy-query-research/power-outer-sources/effects";
var originalVsCode=File.ReadAllBytes(Path.Combine(effects,"vs_GalaxyMapFocusBillboard_Forward_0_Win64_SM50.dxbc"));
var originalPsCode=File.ReadAllBytes(Path.Combine(effects,"ps_GalaxyMapFocusBillboard_Forward_0_Win64_SM50.dxbc"));
using var translatedVs=device.CreateVertexShader(translatedVsCode.Span);using var translatedPs=device.CreatePixelShader(translatedPsCode.Span);
using var originalVs=device.CreateVertexShader(originalVsCode);using var originalPs=device.CreatePixelShader(originalPsCode);
InputElementDescription[] elements=[new("POSITION",0,Format.R32G32B32A32_Float,0,0,InputClassification.PerInstanceData,1),
new("UAXISEXTENT",0,Format.R32G32B32A32_Float,16,0,InputClassification.PerInstanceData,1),
new("VAXISEXTENT",0,Format.R32G32B32A32_Float,32,0,InputClassification.PerInstanceData,1),
new("USERDATA",0,Format.R32G32B32A32_Float,48,0,InputClassification.PerInstanceData,1)];
using var layout=device.CreateInputLayout(elements,translatedVsCode.Span);
// Deliberately wide synthetic billboard samples the PS over many pixels. It is
// only a shader fixture; it is never inserted into the game/source catalogue.
var instance=new GalaxyOriginalPowerActivityBillboard(new(0,0,0,1),new(1,0,0,20),new(0,0,1,20),new(2,1,.5f,0));
using var instances=device.CreateBuffer<GalaxyOriginalPowerActivityBillboard>(new[]{instance},BindFlags.VertexBuffer);
var camera=GalaxyCamera.Create(new(0,0,0),width,height,0,1.25,7);
var eye=camera.Eye;var right=camera.Right;var up=camera.Up;var forward=camera.Forward;
var original0=new Vector4[12];original0[9]=new((float)right.X,(float)right.Y,(float)right.Z,-(float)(right.X*eye.X+right.Y*eye.Y+right.Z*eye.Z));
original0[10]=new((float)up.X,(float)up.Y,(float)up.Z,-(float)(up.X*eye.X+up.Y*eye.Y+up.Z*eye.Z));
original0[11]=new((float)forward.X,(float)forward.Y,(float)forward.Z,-(float)(forward.X*eye.X+forward.Y*eye.Y+forward.Z*eye.Z));
var original1=new Vector4[333];original1[90]=new(0,1,0,0);original1[270]=new((float)(camera.FocalLength/(width*.5)),0,0,0);
original1[271]=new(0,(float)(camera.FocalLength/(height*.5)),0,0);original1[272]=new(0,0,0,1);original1[273]=new(0,0,(float)camera.Near,0);
original1[332]=new(width,height,0,0);
float Int(int value)=>BitConverter.Int32BitsToSingle(value);
Vector4[] original2=[new(Int(1),Int(2),1,Int(0)),new(-20,20,.9f,.75f),new(.92f,.175f,1.5f,.005f)];
using var cb0=device.CreateBuffer<Vector4>(original0,BindFlags.ConstantBuffer);using var cb1=device.CreateBuffer<Vector4>(original1,BindFlags.ConstantBuffer);
using var cb2=device.CreateBuffer<Vector4>(original2,BindFlags.ConstantBuffer);
var translated=new Frame(new((float)eye.X,(float)eye.Y,(float)eye.Z,(float)camera.FocalLength),
new((float)right.X,(float)right.Y,(float)right.Z,width),new((float)up.X,(float)up.Y,(float)up.Z,height),
new((float)forward.X,(float)forward.Y,(float)forward.Z,(float)camera.Near),new(.9f,.75f,.92f,.175f),new(1.5f,.005f,width,height),new(1,1,0,0));
using var cb11=device.CreateBuffer((uint)Marshal.SizeOf<Frame>(),BindFlags.ConstantBuffer);context.UpdateSubresource(in translated,cb11);
var exposure=new[]{new Vector4(8),new Vector4(8)};ID3D11Texture2D exposureTexture;
unsafe{fixed(Vector4* p=exposure)exposureTexture=device.CreateTexture2D(new Texture2DDescription{Width=2,Height=1,Format=Format.R32G32B32A32_Float,ArraySize=1,MipLevels=1,
SampleDescription=new(1,0),Usage=ResourceUsage.Immutable,BindFlags=BindFlags.ShaderResource},[new SubresourceData((nint)p,32,32)]);}
using var et=exposureTexture;using var exposureView=device.CreateShaderResourceView(et);
float[] Draw(bool source,int repeats=1,bool ownedExposure=false)
{
var selected=translated with{Output=new(1,1,ownedExposure?1:0,0)};context.UpdateSubresource(in selected,cb11);
context.OMSetRenderTargets(target);context.ClearRenderTargetView(target,new Color4(0,0,0,0));context.RSSetViewport(new Viewport(width,height));
context.RSSetState(raster);context.OMSetDepthStencilState(depth);context.OMSetBlendState(blend);context.IASetInputLayout(layout);
context.IASetPrimitiveTopology(PrimitiveTopology.TriangleStrip);context.IASetVertexBuffer(0,instances,64);
context.VSSetShader(source?originalVs:translatedVs);context.PSSetShader(source?originalPs:translatedPs);
context.VSSetConstantBuffer(0,cb0);context.VSSetConstantBuffer(1,cb1);context.VSSetConstantBuffer(2,cb2);
context.PSSetConstantBuffer(1,cb1);context.PSSetConstantBuffer(2,cb2);context.PSSetShaderResource(0,exposureView);
context.PSSetShaderResource(20,ownedExposure?exposureView:null!);
context.VSSetConstantBuffer(12,cb11);context.PSSetConstantBuffer(12,cb11);
for(var i=0;i<repeats;i++)context.DrawInstanced(4,1,0,0);
context.PSSetShaderResource(20,null!);
context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());context.CopyResource(staging,texture);
var mapped=context.Map(staging,0,MapMode.Read);var values=new float[width*height*4];
for(var row=0;row<height;row++)Marshal.Copy(mapped.DataPointer+(int)(row*mapped.RowPitch),values,row*width*4,width*4);
context.Unmap(staging,0);return values;
}
var source=Draw(true);var port=Draw(false);var doubled=Draw(false,2);var ownedPort=Draw(false,1,true);
Require(source.All(float.IsFinite)&&port.All(float.IsFinite),"Non-finite shader output");
var maximum=source.Zip(port,(a,b)=>Math.Abs(a-b)).Max();var mean=source.Zip(port,(a,b)=>Math.Abs(a-b)).Average();
var lit=source.Where((_,i)=>i%4==0).Count(v=>v>1e-6);Require(lit>100,"Original shader did not produce contour samples");
Require(maximum<.01&&mean<.0001,"Original/translated FocusBillboard shader mismatch: "+maximum+" / "+mean);
Require(port.Where((_,i)=>i%4==3).All(v=>v==0),"Original range alpha0 changed");
Require(port.Zip(doubled,(a,b)=>Math.Abs(b-2*a)).Max()<1e-6,"Original additive blend changed");
Require(source.Zip(ownedPort,(a,b)=>Math.Abs(a-b)).Max()<.01,"Owned exposure texture did not match original texel1/type2 sampling");
XFEEDToolBox.Rendering.GalaxyGraphics.ValidateBillboardProduction(device,context,shader,camera,instance,target,texture,staging);
var report=new{passed=true,gameAccess=false,sourceDxbcGpuCompared=true,primitive="TriangleStrip",vertexCount=4,litPixels=lit,maximumError=maximum,meanError=mean,
explicitSyntheticEmissiveRescaling=1,originalRuntimeEmissiveResolved=false,productionUnknownSourceMustRemainHidden=true,
productionPartialSourceLinked=true,productionUnknownGateTested=true,productionOwnedManualExposureTested=true,sourceExtentNotRadius=true,
shaderSha256=Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(shader))),originalVsSha256=Convert.ToHexStringLower(SHA256.HashData(originalVsCode)),
originalPsSha256=Convert.ToHexStringLower(SHA256.HashData(originalPsCode))};
File.WriteAllText(Path.Combine(output,"result.json"),JsonSerializer.Serialize(report,new JsonSerializerOptions{WriteIndented=true}));Console.WriteLine(JsonSerializer.Serialize(report));
[StructLayout(LayoutKind.Sequential)] readonly record struct Frame(Vector4 EyeFocal,Vector4 RightWidth,Vector4 UpHeight,Vector4 ForwardNear,Vector4 Material,Vector4 Highlight,Vector4 Output);
namespace XFEEDToolBox.Rendering
{
internal sealed partial class GalaxyGraphics
{
private ID3D11Device device=null!;private ID3D11DeviceContext context=null!;private int width=256,height=256,DrawCalls;
private void Upload<T>(ID3D11Buffer buffer,ReadOnlySpan<T> values)where T:unmanaged
{var mapped=context.Map(buffer,0,MapMode.WriteDiscard);unsafe{values.CopyTo(new Span<T>((void*)mapped.DataPointer,values.Length));}context.Unmap(buffer,0);}
internal static void ValidateBillboardProduction(ID3D11Device device,ID3D11DeviceContext context,string shader,GalaxyCamera camera,GalaxyOriginalPowerActivityBillboard value,
ID3D11RenderTargetView target,ID3D11Texture2D texture,ID3D11Texture2D staging)
{
var graphics=new GalaxyGraphics{device=device,context=context};graphics.InitializeOriginalPowerActivityBillboard(shader);
try
{
graphics.SetOriginalPowerActivityBillboard(value);graphics.DrawOriginalPowerActivityBillboard(camera,1);
if(!graphics.PowerActivityBillboardSourceUnknown||graphics.SubmittedPowerActivityBillboards!=0)throw new InvalidOperationException("Unknown exposure source produced contour");
graphics.InitializeOriginalExposure(shader);graphics.DrawOriginalPowerActivityBillboard(camera,1);
if(graphics.SubmittedPowerActivityBillboards!=0)throw new InvalidOperationException("Zero default was made visible");
graphics.ComputeOriginalManualExposure();context.OMSetRenderTargets(target);context.ClearRenderTargetView(target,new Color4(0,0,0,0));
graphics.DrawOriginalPowerActivityBillboard(camera,1);
if(graphics.PowerActivityBillboardSourceUnknown||graphics.SubmittedPowerActivityBillboards!=1)throw new InvalidOperationException("Owned manual exposure did not reach billboard");
context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());context.CopyResource(staging,texture);
var mapped=context.Map(staging,0,MapMode.Read);var row=new float[256*4];var lit=0;
for(var y=0;y<256;y++){Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),row,0,row.Length);for(var x=0;x<row.Length;x+=4)if(float.IsFinite(row[x])&&row[x]>1e-6)lit++;}
context.Unmap(staging,0);if(lit<100)throw new InvalidOperationException("Production contour had no pixels");
graphics.SetOriginalPowerActivityBillboard(null);graphics.DrawOriginalPowerActivityBillboard(camera,1);
if(graphics.SubmittedPowerActivityBillboards!=0)throw new InvalidOperationException("Missing bound rendered contour");
}
finally{graphics.DisposeOriginalExposure();graphics.DisposeOriginalPowerActivityBillboard();}
}
}
}