using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text.Json;
using Cosmos.Kernel.System.Graphics;
using XFESystem.Browser;
using XFESystem.Desktop;
using XFESystem.Kernel;
using XfePaintBaseline;
System.Runtime.Loader.AssemblyLoadContext.Default.Resolving += (_, name) =>
{
string path = Path.Combine(AppContext.BaseDirectory, name.Name + ".dll");
return File.Exists(path) ? System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(path) : null;
};
Probe.Run(args);
static class Probe
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Run(string[] args)
{
string root = Path.GetFullPath(args.Length > 0 ? args[0] : ".");
string output = Path.GetFullPath(args.Length > 1 ? args[1] : Path.Combine(root, "build", "PaintPerformance-" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()));
Directory.CreateDirectory(output);
var baseline = Create(typeof(BaselineCanvasAdapter), root);
var current = Create(typeof(CanvasAdapter), root);
string markdown = File.ReadAllText(Path.Combine(root, "Source/XFESystem.Documents/Assets/Website/Fixtures/WebsiteParity.md"));
var results = new List<object>();
foreach (bool dark in new[] { true, false })
{
var browser = new BrowserService();
browser.SetCanvas((IDesktopCanvas)current);
browser.NavigateDocument(markdown, "WebsiteParity.md", dark);
var list = browser.Layout(new(796, 404));
var viewport = new DesktopBounds(0, 0, 796, 404);
int[] before = Pixels(baseline), after = Pixels(current);
Array.Clear(before); Array.Clear(after);
var oldCold = Time(() => BaselinePagePainter.Paint((IDesktopCanvas)baseline, viewport, list));
var newCold = Time(() => BrowserRasterPainter.Paint((IDesktopCanvas)current, viewport, list));
string oldHash = Hash(before), newHash = Hash(after);
int differing = before.Zip(after).Count(pair => pair.First != pair.Second);
if (differing != 0) throw new InvalidOperationException("Raster pixels changed: " + differing);
var snapshot = BrowserPaintSnapshot.Capture(list);
Array.Clear(after); snapshot.Paint((IDesktopCanvas)current, viewport);
if (Hash(after) != newHash) throw new InvalidOperationException("Frozen DOM-free snapshot changed actual font/CSS raster pixels.");
const int iterations = 8;
var oldWarm = Time(() => { for (int i = 0; i < iterations; i++) BaselinePagePainter.Paint((IDesktopCanvas)baseline, viewport, list); });
var newWarm = Time(() => { for (int i = 0; i < iterations; i++) BrowserRasterPainter.Paint((IDesktopCanvas)current, viewport, list); });
var native = (CanvasAdapter)current;
native.BeginScene(viewport); native.StoreWebFrame(dark ? 1 : 2, 1, 1, viewport, 0, 0);
var expected = (int[])after.Clone(); Array.Fill(after, -123);
if (!native.TryRestoreWebFrame(dark ? 1 : 2, 1, 1, viewport, 0, 0)) throw new Exception("Native website frame cache missed its full capture.");
for (int y = 0; y < 900; y++) for (int x = 0; x < 1600; x++)
if (after[y * 1600 + x] != (x < 1592 && y < 808 ? expected[y * 1600 + x] : -123)) throw new Exception("Native website cache pixels changed.");
const int restoreIterations = 64;
double restoreTime = Time(() => { for (int i = 0; i < restoreIterations; i++) native.TryRestoreWebFrame(dark ? 1 : 2, 1, 1, viewport, 0, 0); }) / restoreIterations;
results.Add(new { Dark = dark, Commands = list.Commands.Count, DocumentHeight = list.DocumentHeight,
NativeWidth = 1600, NativeHeight = 900, CssViewport = viewport, ScalePercent = 200,
BaselineColdMilliseconds = oldCold, CurrentColdMilliseconds = newCold,
Iterations = iterations, BaselineWarmMillisecondsPerFrame = oldWarm / iterations,
CurrentWarmMillisecondsPerFrame = newWarm / iterations, WarmSpeedup = oldWarm / newWarm,
FrameCacheRestoreMillisecondsPerFrame = restoreTime, FrameCacheRestoredPixelsExact = true,
BaselinePixelsSha256 = oldHash, CurrentPixelsSha256 = newHash, DifferingPixels = differing, ExactPixels = true,
FrozenSnapshotPixelsExact = true, FrozenSnapshotNodeReferences = snapshot.Commands.Count(command => command.Node is not null) });
}
var live = (CanvasAdapter)current;
var measures = new List<object>();
foreach (int weight in new[] { 400, 700 })
foreach (string family in new[] { "Consolas", "system-ui", "bootstrap-icons" })
foreach (string text in new[] { "WWW iii AV Tof = 42;", "中文文档预览,这是测试。", "using System; var value = 3;", "\uf475\uf30a\uf14d\uf759" })
{
var old = (IDesktopWebCanvas)baseline;
double expected = old.MeasureWebText(text, 14.25, family, weight);
double actual = live.MeasureWebText(text, 14.25, family, weight);
if (actual != expected) throw new Exception("Font widths changed.");
var a = old.RasterizeWebText(text, 14.25, family, weight); var b = live.RasterizeWebText(text, 14.25, family, weight);
if (a.Width != b.Width || a.Height != b.Height || !a.Alpha.AsSpan().SequenceEqual(b.Alpha)) throw new Exception("Font alpha changed.");
b.Alpha.AsSpan().Fill(0); var again = live.RasterizeWebText(text, 14.25, family, weight);
if (!a.Alpha.AsSpan().SequenceEqual(again.Alpha)) throw new Exception("Writable caller mask corrupted cached data.");
measures.Add(new { Family = family, Weight = weight, Text = text, Width = actual, MaskSha256 = Convert.ToHexStringLower(SHA256.HashData(a.Alpha)), Exact = true, WritableCopyIsolated = true });
}
var clock = Stopwatch.StartNew();
for (int i = 0; i < 4096; i++) live.MeasureWebText("Unique" + i, 1 + i % 128, "Consolas", 400);
for (int i = 0; i < 1100; i++) live.RasterizeWebText("Mask" + i, 14, "Consolas", 400);
if (live.CachedWebTextMaskCount > 1024 || live.CachedWebTextMaskBytes > 2097152) throw new Exception("Text mask cache exceeded its bound.");
var counts = new Dictionary<string,int>();
foreach(var pair in new[]{("webGlyphPresence",8192),("webAdvances",8192),("webKernings",4096),("webTextWidths",2048)})
{
var dictionary=(System.Collections.IDictionary)typeof(CanvasAdapter).GetField(pair.Item1,BindingFlags.NonPublic|BindingFlags.Instance)!.GetValue(live)!;
counts[pair.Item1]=dictionary.Count;if(dictionary.Count>pair.Item2)throw new Exception("Font cache exceeded bound: "+pair.Item1);
}
var result = new { Schema = "XfeSoftwarePaintPerformance1", Passed = true, HostOnly = true, GuestAcceptance = false,
Note = "Executes production software painter, CanvasAdapter and pinned Cosmos TrueTypeFont on a private host framebuffer. Frozen pre-optimization baseline shares the exact same website display list. Timings are host CPU timings, not QEMU FPS or GPU evidence.",
Cases = results, FontChecks = measures,
CacheBounds = new { live.CachedWebTextMaskCount, live.CachedWebTextMaskBytes, MaximumEntries = 1024, MaximumBytes = 2097152, OtherCacheEntries = counts, live.WebTextMeasureCacheHits, live.WebTextMaskCacheHits, Passed = true },
NativeFrameCache = CheckNativeFrameCache(root),
NativeRenderYield = CheckNativeRenderYield(root),
NativeAbortAndCoverage = CheckNativeAbortAndCoverage(root),
NativeMotionFrameCache = CheckNativeMotionFrameCache(root),
NativeEditorPreparationHandoff = CheckEditorPreparationHandoff(root),
SourceHashes = new[] { "Source/XFESystem.Browser/BrowserBoxDecoration.cs", "Source/XFESystem.Browser/BrowserCssGradient.cs", "Source/XFESystem.Browser/BrowserClipRasterCanvas.cs", "Source/XFESystem.Kernel/CanvasAdapter.cs", "Source/XFESystem.Desktop/IDesktopWebFrameCache.cs", "Source/XFESystem.Desktop/IDesktopRenderYieldCanvas.cs", "Source/XFESystem.Kernel/NativeKeyboardCapture.cs", "Source/XFESystem.Kernel/NativePointerCapture.cs" }
.ToDictionary(path => path, path => Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(Path.Combine(root,path))))) };
string json = JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(Path.Combine(output, "Result.json"), json); Console.WriteLine(json);
}
private static double Time(Action action) { var timer = Stopwatch.StartNew(); action(); return timer.Elapsed.TotalMilliseconds; }
private static string Hash(int[] pixels) => Convert.ToHexStringLower(SHA256.HashData(System.Runtime.InteropServices.MemoryMarshal.AsBytes(pixels.AsSpan())));
private static int[] Pixels(object target) => (int[])target.GetType().GetField("pixels", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(target)!;
private static object CheckEditorPreparationHandoff(string root)
{
var prepared = (CanvasAdapter)Create(typeof(CanvasAdapter), root);
var main = (CanvasAdapter)Create(typeof(CanvasAdapter), root);
var cold = (CanvasAdapter)Create(typeof(CanvasAdapter), root);
var mismatch = (CanvasAdapter)Create(typeof(CanvasAdapter), root);
void Set(CanvasAdapter target, string name, object value) => typeof(CanvasAdapter).GetField(name, BindingFlags.NonPublic | BindingFlags.Instance)!.SetValue(target, value);
int Count(CanvasAdapter target, string name) => ((System.Collections.IDictionary)typeof(CanvasAdapter).GetField(name, BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(target)!).Count;
Set(prepared, "preparationOnly", true); Set(mismatch, "scale", 1);
Array.Fill(Pixels(prepared), -123); Array.Fill(Pixels(main), -123);
string preparedPixels = Hash(Pixels(prepared)), mainPixels = Hash(Pixels(main));
var samples = new[] { (Text: "using System; public class XFE { int value = 42; }", Family: "Consolas", Weight: 400),
(Text: "中文 C# Preview", Family: "system-ui", Weight: 700), (Text: "\uf475\uf30a", Family: "bootstrap-icons", Weight: 400) };
foreach (var sample in samples)
{
prepared.MeasureWebText(sample.Text, 13, sample.Family, sample.Weight);
prepared.PrepareEditorText(sample.Text, 13, sample.Family, sample.Weight);
prepared.RasterizeWebText(sample.Text, 13, sample.Family, sample.Weight);
}
prepared.MeasureWebText("中文", 13, "system-ui", 400);
main.MeasureWebText("中文", 13, "system-ui", 400);
object CjkFont(CanvasAdapter value)
{
var fonts = (System.Collections.IDictionary)typeof(CanvasAdapter).GetField("webFonts", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(value)!;
object face = fonts[10]!;
return face.GetType().GetProperty("Font")!.GetValue(face)!;
}
var preparedFont = (Cosmos.Kernel.System.Graphics.Fonts.TrueTypeFont)CjkFont(prepared);
var mainFont = (Cosmos.Kernel.System.Graphics.Fonts.TrueTypeFont)CjkFont(main);
if (ReferenceEquals(preparedFont, mainFont) || !ReferenceEquals(preparedFont.Data, mainFont.Data)) throw new Exception("Font resource bytes are duplicated or mutable font caches are shared.");
string resourceHash = Convert.ToHexStringLower(SHA256.HashData(preparedFont.Data));
prepared.PrepareEditorText("中文", 13, "system-ui", 400);
prepared.RasterizeWebText("中文", 13, "system-ui", 400);
main.RasterizeWebText("中文", 13, "system-ui", 400);
if (resourceHash != Convert.ToHexStringLower(SHA256.HashData(mainFont.Data))) throw new Exception("The pinned font parser/rasterizer mutated shared font resource bytes.");
int warmedGlyphs = Count(prepared, "webGlyphs");
if (warmedGlyphs == 0 || preparedPixels != Hash(Pixels(prepared)) || mainPixels != Hash(Pixels(main))) throw new Exception("Editor preparation did not warm real glyphs without touching pixels.");
if (prepared.TryCompleteEditorPreparationHandoff(mismatch) || main.TryCompleteEditorPreparationHandoff(prepared) || prepared.TryCompleteEditorPreparationHandoff(prepared)) throw new Exception("Editor handoff accepted an incompatible canvas.");
if (!prepared.TryCompleteEditorPreparationHandoff(main) || !prepared.TryCompleteEditorPreparationHandoff(main) || prepared.TryCompleteEditorPreparationHandoff(cold)) throw new Exception("Editor handoff was not exclusive and idempotent.");
if (warmedGlyphs != Count(main, "webGlyphs") || preparedPixels != Hash(Pixels(prepared)) || mainPixels != Hash(Pixels(main))) throw new Exception("Editor handoff lost glyphs or changed pixels.");
Array.Clear(Pixels(main)); Array.Clear(Pixels(cold)); main.BeginScene(new(0, 0, 800, 450)); cold.BeginScene(new(0, 0, 800, 450));
long hitsBefore = main.WebTextMeasureCacheHits;
int glyphsBefore = Count(main, "webGlyphs"), y = 4;
foreach (var sample in samples)
{
if (main.MeasureWebText(sample.Text, 13, sample.Family, sample.Weight) != cold.MeasureWebText(sample.Text, 13, sample.Family, sample.Weight)) throw new Exception("Prepared metrics differ from the actual main canvas.");
main.WebText(sample.Text, 0xAC99EA, 4, y, 13, sample.Family, sample.Weight);
cold.WebText(sample.Text, 0xAC99EA, 4, y, 13, sample.Family, sample.Weight);
y += 24;
}
if (Hash(Pixels(main)) != Hash(Pixels(cold)) || glyphsBefore != Count(main, "webGlyphs") || main.WebTextMeasureCacheHits - hitsBefore < samples.Length) throw new Exception("Prepared native glyph handoff changed pixels or missed the scanout glyph cache.");
bool rejectedAfterHandoff = false;
try { prepared.PrepareEditorText("not owned by worker", 13, "Consolas", 400); } catch (InvalidOperationException) { rejectedAfterHandoff = true; }
if (!rejectedAfterHandoff) throw new Exception("Worker preparation remained available after ownership transfer.");
var mask = main.RasterizeWebText(samples[0].Text, 13, "Consolas", 400); string maskHash = Convert.ToHexStringLower(SHA256.HashData(mask.Alpha)); mask.Alpha.AsSpan().Clear();
if (maskHash != Convert.ToHexStringLower(SHA256.HashData(main.RasterizeWebText(samples[0].Text, 13, "Consolas", 400).Alpha))) throw new Exception("A writable caller corrupted a transferred mask.");
return new { Passed = true, ActualTrueTypeFonts = true, ScalePercent = 200, CssFontSize = 13, NativeGlyphSize = 26,
PreparedNativeGlyphs = warmedGlyphs, ExactColdRasterPixels = true, NoGlyphRasterizationAfterHandoff = true,
PreparationAndHandoffDoNotWritePixels = true, IncompatibleTargetRejected = true, ExclusiveAndIdempotent = true,
WorkerPreparationRejectedAfterHandoff = true, WritableMaskIsolated = true,
SharedImmutableCjkBytes = preparedFont.Data.Length, SharedFontResourceHashUnchanged = true,
IndependentMutableTrueTypeFontObjects = true };
}
private static object CheckNativeFrameCache(string root)
{
var native = (CanvasAdapter)Create(typeof(CanvasAdapter), root); var pixels = Pixels(native);
for (int i = 0; i < pixels.Length; i++) pixels[i] = unchecked(i * 123457);
var original = (int[])pixels.Clone(); var bounds = new DesktopBounds(10, 20, 30, 25);
native.BeginScene(bounds); native.StoreWebFrame(9, 10, 11, bounds, 0, .25);
Array.Fill(pixels, -123); var damage = new DesktopBounds(21, 27, 2, 3); native.BeginScene(damage);
if (native.WebPaintClip != damage || !native.TryRestoreWebFrame(9, 10, 11, bounds, 0, .25)) throw new Exception("Native damage restore missed.");
for (int y = 0; y < 900; y++) for (int x = 0; x < 1600; x++)
if (pixels[y * 1600 + x] != (x >= 42 && x < 46 && y >= 54 && y < 60 ? original[y * 1600 + x] : -123)) throw new Exception("Native damage restore touched incorrect pixels.");
Array.Fill(pixels, -123); var moved = bounds with { X = 30, Y = 30 }; native.BeginScene(moved);
if (!native.TryRestoreWebFrame(9, 10, 11, moved, 0, .25)) throw new Exception("Window movement invalidated native frame.");
for (int y = 0; y < 900; y++) for (int x = 0; x < 1600; x++)
if (pixels[y * 1600 + x] != (x >= 60 && x < 120 && y >= 60 && y < 110 ? original[(y - 20) * 1600 + x - 40] : -123)) throw new Exception("Native moved restore pixels changed.");
native.BeginScene(damage); native.StoreWebFrame(9, 12, 11, moved, 0, .25);
if (native.TryRestoreWebFrame(9, 12, 11, moved, 0, .25) || native.TryRestoreWebFrame(9, 10, 12, moved, 0, .25) ||
native.TryRestoreWebFrame(9, 10, 11, moved, 0, .5)) throw new Exception("Native stale/partial cache frame was accepted.");
if(native.CachedWebFrameCount != 1 || native.CachedWebFrameBytes != 12000 || native.WebFramePixelsRestored != 3024) throw new Exception("Native cache accounting changed.");
return new { Passed = true, DamagePixelsExact = true, MovedPixelsExact = true, PartialCaptureRejected = true,
RevisionLayoutScrollMissesVerified = true, native.CachedWebFrameCount, native.CachedWebFrameBytes, native.WebFrameRestoreHits, native.WebFramePixelsRestored };
}
private static object CheckNativeRenderYield(string root)
{
NativeKeyboardCapture.Prepare();while(NativeKeyboardCapture.TryRead(out _,out _,out _)){ }
NativePointerCapture.Prepare();while(NativePointerCapture.TryRead(out _)){ }
NativePointerCapture.Observe(0,0,false,false,false,0,0);while(NativePointerCapture.TryRead(out _)){ }
var native=(CanvasAdapter)Create(typeof(CanvasAdapter),root);var pixels=Pixels(native);Array.Fill(pixels,-123);
native.BeginScene(new(0,0,800,450));NativeKeyboardCapture.Observe(0x5B,false);bool yielded=false;
try{native.BlendCoverage(0xFFFFFF,0,0,1,4,new byte[]{255,255,255,255});}catch(DesktopRenderYieldException){yielded=true;}
if(!yielded||pixels.Any(value=>value!=-123)||!NativeKeyboardCapture.HasPendingReports)throw new Exception("Native keyboard render yield consumed input or changed a row.");
if(!NativeKeyboardCapture.TryRead(out var scan,out var released,out var lost)||scan!=0x5B||released||lost)throw new Exception("Native keyboard yield altered raw report.");
NativePointerCapture.Observe(20,30,false,false,false,0,1);
if(native.RenderYieldRequested)throw new Exception("Ordinary pointer motion cancelled native paint.");
native.BlendCoverage(0xFFFFFF,0,0,1,1,new byte[]{255});
if(!NativePointerCapture.TryRead(out var motion)||motion.X!=20||motion.Y!=30)throw new Exception("Native paint consumed motion.");
NativePointerCapture.Observe(20,30,true,false,false,0,2);yielded=false;
try{native.BlendCoverage(0xFFFFFF,0,1,1,1,new byte[]{255});}catch(DesktopRenderYieldException){yielded=true;}
if(!yielded||pixels[1600]!=-123||native.FramesPresented!=0||native.CachedWebFrameCount!=0)throw new Exception("Cancelled native row was cached/presented or painted.");
if(!NativePointerCapture.TryRead(out var down)||!down.LeftButton)throw new Exception("Native render yield consumed the button make.");
NativePointerCapture.Observe(20,30,false,false,false,0,3);while(NativePointerCapture.TryRead(out _)){ }
return new{Passed=true,KeyboardAndButtonYield=true,PendingReportsNotConsumed=true,OrdinaryMotionPaints=true,
CancelledRowUnmodified=true,CancelledFrameNotCachedOrPresented=true};
}
private static object CheckNativeAbortAndCoverage(string root)
{
var native=(CanvasAdapter)Create(typeof(CanvasAdapter),root);
var area=new DesktopBounds(4,3,12,5);
native.BeginScene(new(0,0,800,450));native.PreserveTranslatedSceneRegion(area,area.X,area.Y,true);native.EndScenePreservation();
long PendingPixels()
{
object rectangle=typeof(CanvasAdapter).GetField("unchangedScanout",BindingFlags.NonPublic|BindingFlags.Instance)!.GetValue(native)!;
return (long)(int)rectangle.GetType().GetProperty("Width")!.GetValue(rectangle)!*(int)rectangle.GetType().GetProperty("Height")!.GetValue(rectangle)!;
}
long normalPending=PendingPixels();if(normalPending!=240)throw new Exception("Normal scene end lost the valid scanout optimization.");
native.AbortScenePreservation();native.BeginScene(new(0,0,800,450));
if(PendingPixels()!=0)throw new Exception("Cancelled frame retained a stale scanout copy exclusion.");
var comparisons=new List<object>();var baseline=(BaselineCanvasAdapter)Create(typeof(BaselineCanvasAdapter),root);
int[] old=Pixels(baseline),current=Pixels(native);var random=new Random(74071);
for(int test=0;test<6;test++)
{
for(int i=0;i<old.Length;i++)old[i]=current[i]=random.Next();
baseline.BeginScene(new(0,0,800,450));native.BeginScene(new(0,0,800,450));
if((test&1)!=0)
{
baseline.SaveScene();native.SaveScene();baseline.PreserveTranslatedSceneRegion(area,8,4);native.PreserveTranslatedSceneRegion(area,8,4);
}
const int width=157,height=33;var mask=new byte[width*height];
for(int i=0;i<mask.Length;i++)mask[i]=test/2==0?(byte)255:test/2==1?(byte)0:i%64<8?(byte)0:i%64<40?(byte)255:(byte)(1+i%254);
baseline.BlendCoverage(0x8A72D5,-11,-3,width,height,mask);native.BlendCoverage(0x8A72D5,-11,-3,width,height,mask);
if(!old.AsSpan().SequenceEqual(current))throw new Exception("Native zero/opaque/mixed coverage changed clipped or motion-preserved pixels.");
comparisons.Add(new{Case=test,MotionPreserved=(test&1)!=0,AlphaMode=test/2==0?"Opaque":test/2==1?"Transparent":"Mixed",PixelsSha256=Hash(current),ExactPixels=true});
}
baseline.EndScenePreservation();native.EndScenePreservation();
var opaque=new byte[1280*720];Array.Fill(opaque,(byte)255);const int iterations=16;
double oldTime=Time(()=>{for(int i=0;i<iterations;i++)baseline.BlendCoverage(0x8A72D5,0,0,1280,720,opaque);})/iterations;
double newTime=Time(()=>{for(int i=0;i<iterations;i++)native.BlendCoverage(0x8A72D5,0,0,1280,720,opaque);})/iterations;
if(!old.AsSpan().SequenceEqual(current))throw new Exception("Native opaque benchmark changed pixels.");
return new{Passed=true,NormalEndKeepsScanoutSkipPixels=normalPending,AbortClearsScanoutSkipPixels=PendingPixels(),
CoverageComparisons=comparisons,BaselineOpaqueMilliseconds=oldTime,CurrentOpaqueMilliseconds=newTime,OpaqueSpeedup=oldTime/newTime,
HostOnly=true,NativeFrameAcceptance=false};
}
private static object CheckNativeMotionFrameCache(string root)
{
var native=(CanvasAdapter)Create(typeof(CanvasAdapter),root);var pixels=Pixels(native);
const int blue=unchecked((int)0xff0000ff),red=unchecked((int)0xffef3344);
Array.Fill(pixels,blue);var viewport=new DesktopBounds(0,0,40,30);native.BeginScene(new(0,0,800,450));
native.StoreWebFrame(1,1,1,viewport,0,0);
for(int y=6;y<16;y++)for(int x=8;x<32;x++)pixels[y*1600+x]=red;
native.SaveScene();native.PreserveTranslatedSceneRegion(new(4,3,12,5),6,4);
if(!native.TryRestoreWebFrame(1,1,1,viewport,0,0))throw new Exception("Protected background cache missed.");
for(int y=0;y<60;y++)for(int x=0;x<80;x++)
if(pixels[y*1600+x]!=(x>=12&&x<36&&y>=8&&y<18?red:blue))throw new Exception("Background frame cache overwrote a moved foreground window.");
if(native.WebFramePixelsRestored!=4560)throw new Exception("Protected motion pixels were counted as actual restored pixels.");
native.Fill(0x0000ff,0,0,40,30);native.StoreWebFrame(2,1,1,viewport,0,0);
if(native.WebFrameCaptures!=1)throw new Exception("Protected foreground pixels were captured as a background browser frame.");
native.AbortScenePreservation();native.BeginScene(new(0,0,800,450));Array.Fill(pixels,0);
if(native.TryRestoreWebFrame(2,1,1,viewport,0,0))throw new Exception("A partly obscured viewport was cached.");
if(!native.TryRestoreWebFrame(1,1,1,viewport,0,0))throw new Exception("Rejected motion capture evicted the good frame.");
for(int y=0;y<60;y++)for(int x=0;x<80;x++)if(pixels[y*1600+x]!=blue)throw new Exception("Good browser frame contains foreground pixels.");
return new{Passed=true,ForegroundPreservedPixels=240,ActualRestoredPixelsBeforeAbort=4560,
BackgroundCaptureRejected=true,GoodFramePreserved=true,ActualRestoredPixelsTotal=native.WebFramePixelsRestored,
Captures=native.WebFrameCaptures,HostOnly=true,NativeFrameAcceptance=false};
}
private static object Create(Type type, string root)
{
// Avoid firmware/HAL initialization on the host. Only the backing canvas,
// font dictionaries and clipping state used by the real painter are set.
object target = RuntimeHelpers.GetUninitializedObject(type);
const int width = 1600, height = 900;
var surface = new Canvas(width, height); int[] pixels = surface.GetBuffer()!; var scene = new int[pixels.Length];
void Set(string name, object value) => type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance)!.SetValue(target, value);
foreach (var field in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) field.SetValue(target, Activator.CreateInstance(field.FieldType));
else if(field.FieldType == typeof(DesktopWebFrameCache)) field.SetValue(target,new DesktopWebFrameCache());
}
Set("canvas", surface); Set("scale", 2); Set("pixels", pixels); Set("scene", scene);
Set("motion", new DesktopSceneMotionBuffer(pixels, scene, width, height));
Set("unicode", File.ReadAllBytes(Path.Combine(root, "assets/branding/console/xfe-unicode.bin")));
var clip = type.GetField("clip", BindingFlags.NonPublic | BindingFlags.Instance)!;
clip.SetValue(target, Activator.CreateInstance(clip.FieldType, 0, 0, width, height));
var clips = type.GetField("webClips", BindingFlags.NonPublic | BindingFlags.Instance)!;
clips.SetValue(target, Activator.CreateInstance(clips.FieldType));
return target;
}
}
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text.Json;
using Cosmos.Kernel.System.Graphics;
using XFESystem.Browser;
using XFESystem.Desktop;
using XFESystem.Kernel;
using XfePaintBaseline;
System.Runtime.Loader.AssemblyLoadContext.Default.Resolving += (_, name) =>
{
string path = Path.Combine(AppContext.BaseDirectory, name.Name + ".dll");
return File.Exists(path) ? System.Runtime.Loader.AssemblyLoadContext.Default.LoadFromAssemblyPath(path) : null;
};
Probe.Run(args);
static class Probe
{
[MethodImpl(MethodImplOptions.NoInlining)]
public static void Run(string[] args)
{
string root = Path.GetFullPath(args.Length > 0 ? args[0] : ".");
string output = Path.GetFullPath(args.Length > 1 ? args[1] : Path.Combine(root, "build", "PaintPerformance-" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()));
Directory.CreateDirectory(output);
var baseline = Create(typeof(BaselineCanvasAdapter), root);
var current = Create(typeof(CanvasAdapter), root);
string markdown = File.ReadAllText(Path.Combine(root, "Source/XFESystem.Documents/Assets/Website/Fixtures/WebsiteParity.md"));
var results = new List<object>();
foreach (bool dark in new[] { true, false })
{
var browser = new BrowserService();
browser.SetCanvas((IDesktopCanvas)current);
browser.NavigateDocument(markdown, "WebsiteParity.md", dark);
var list = browser.Layout(new(796, 404));
var viewport = new DesktopBounds(0, 0, 796, 404);
int[] before = Pixels(baseline), after = Pixels(current);
Array.Clear(before); Array.Clear(after);
var oldCold = Time(() => BaselinePagePainter.Paint((IDesktopCanvas)baseline, viewport, list));
var newCold = Time(() => BrowserRasterPainter.Paint((IDesktopCanvas)current, viewport, list));
string oldHash = Hash(before), newHash = Hash(after);
int differing = before.Zip(after).Count(pair => pair.First != pair.Second);
if (differing != 0) throw new InvalidOperationException("Raster pixels changed: " + differing);
var snapshot = BrowserPaintSnapshot.Capture(list);
Array.Clear(after); snapshot.Paint((IDesktopCanvas)current, viewport);
if (Hash(after) != newHash) throw new InvalidOperationException("Frozen DOM-free snapshot changed actual font/CSS raster pixels.");
const int iterations = 8;
var oldWarm = Time(() => { for (int i = 0; i < iterations; i++) BaselinePagePainter.Paint((IDesktopCanvas)baseline, viewport, list); });
var newWarm = Time(() => { for (int i = 0; i < iterations; i++) BrowserRasterPainter.Paint((IDesktopCanvas)current, viewport, list); });
var native = (CanvasAdapter)current;
native.BeginScene(viewport); native.StoreWebFrame(dark ? 1 : 2, 1, 1, viewport, 0, 0);
var expected = (int[])after.Clone(); Array.Fill(after, -123);
if (!native.TryRestoreWebFrame(dark ? 1 : 2, 1, 1, viewport, 0, 0)) throw new Exception("Native website frame cache missed its full capture.");
for (int y = 0; y < 900; y++) for (int x = 0; x < 1600; x++)
if (after[y * 1600 + x] != (x < 1592 && y < 808 ? expected[y * 1600 + x] : -123)) throw new Exception("Native website cache pixels changed.");
const int restoreIterations = 64;
double restoreTime = Time(() => { for (int i = 0; i < restoreIterations; i++) native.TryRestoreWebFrame(dark ? 1 : 2, 1, 1, viewport, 0, 0); }) / restoreIterations;
results.Add(new { Dark = dark, Commands = list.Commands.Count, DocumentHeight = list.DocumentHeight,
NativeWidth = 1600, NativeHeight = 900, CssViewport = viewport, ScalePercent = 200,
BaselineColdMilliseconds = oldCold, CurrentColdMilliseconds = newCold,
Iterations = iterations, BaselineWarmMillisecondsPerFrame = oldWarm / iterations,
CurrentWarmMillisecondsPerFrame = newWarm / iterations, WarmSpeedup = oldWarm / newWarm,
FrameCacheRestoreMillisecondsPerFrame = restoreTime, FrameCacheRestoredPixelsExact = true,
BaselinePixelsSha256 = oldHash, CurrentPixelsSha256 = newHash, DifferingPixels = differing, ExactPixels = true,
FrozenSnapshotPixelsExact = true, FrozenSnapshotNodeReferences = snapshot.Commands.Count(command => command.Node is not null) });
}
var live = (CanvasAdapter)current;
var measures = new List<object>();
foreach (int weight in new[] { 400, 700 })
foreach (string family in new[] { "Consolas", "system-ui", "bootstrap-icons" })
foreach (string text in new[] { "WWW iii AV Tof = 42;", "中文文档预览,这是测试。", "using System; var value = 3;", "\uf475\uf30a\uf14d\uf759" })
{
var old = (IDesktopWebCanvas)baseline;
double expected = old.MeasureWebText(text, 14.25, family, weight);
double actual = live.MeasureWebText(text, 14.25, family, weight);
if (actual != expected) throw new Exception("Font widths changed.");
var a = old.RasterizeWebText(text, 14.25, family, weight); var b = live.RasterizeWebText(text, 14.25, family, weight);
if (a.Width != b.Width || a.Height != b.Height || !a.Alpha.AsSpan().SequenceEqual(b.Alpha)) throw new Exception("Font alpha changed.");
b.Alpha.AsSpan().Fill(0); var again = live.RasterizeWebText(text, 14.25, family, weight);
if (!a.Alpha.AsSpan().SequenceEqual(again.Alpha)) throw new Exception("Writable caller mask corrupted cached data.");
measures.Add(new { Family = family, Weight = weight, Text = text, Width = actual, MaskSha256 = Convert.ToHexStringLower(SHA256.HashData(a.Alpha)), Exact = true, WritableCopyIsolated = true });
}
var clock = Stopwatch.StartNew();
for (int i = 0; i < 4096; i++) live.MeasureWebText("Unique" + i, 1 + i % 128, "Consolas", 400);
for (int i = 0; i < 1100; i++) live.RasterizeWebText("Mask" + i, 14, "Consolas", 400);
if (live.CachedWebTextMaskCount > 1024 || live.CachedWebTextMaskBytes > 2097152) throw new Exception("Text mask cache exceeded its bound.");
var counts = new Dictionary<string,int>();
foreach(var pair in new[]{("webGlyphPresence",8192),("webAdvances",8192),("webKernings",4096),("webTextWidths",2048)})
{
var dictionary=(System.Collections.IDictionary)typeof(CanvasAdapter).GetField(pair.Item1,BindingFlags.NonPublic|BindingFlags.Instance)!.GetValue(live)!;
counts[pair.Item1]=dictionary.Count;if(dictionary.Count>pair.Item2)throw new Exception("Font cache exceeded bound: "+pair.Item1);
}
var result = new { Schema = "XfeSoftwarePaintPerformance1", Passed = true, HostOnly = true, GuestAcceptance = false,
Note = "Executes production software painter, CanvasAdapter and pinned Cosmos TrueTypeFont on a private host framebuffer. Frozen pre-optimization baseline shares the exact same website display list. Timings are host CPU timings, not QEMU FPS or GPU evidence.",
Cases = results, FontChecks = measures,
CacheBounds = new { live.CachedWebTextMaskCount, live.CachedWebTextMaskBytes, MaximumEntries = 1024, MaximumBytes = 2097152, OtherCacheEntries = counts, live.WebTextMeasureCacheHits, live.WebTextMaskCacheHits, Passed = true },
NativeFrameCache = CheckNativeFrameCache(root),
NativeRenderYield = CheckNativeRenderYield(root),
NativeAbortAndCoverage = CheckNativeAbortAndCoverage(root),
NativeMotionFrameCache = CheckNativeMotionFrameCache(root),
NativeEditorPreparationHandoff = CheckEditorPreparationHandoff(root),
SourceHashes = new[] { "Source/XFESystem.Browser/BrowserBoxDecoration.cs", "Source/XFESystem.Browser/BrowserCssGradient.cs", "Source/XFESystem.Browser/BrowserClipRasterCanvas.cs", "Source/XFESystem.Kernel/CanvasAdapter.cs", "Source/XFESystem.Desktop/IDesktopWebFrameCache.cs", "Source/XFESystem.Desktop/IDesktopRenderYieldCanvas.cs", "Source/XFESystem.Kernel/NativeKeyboardCapture.cs", "Source/XFESystem.Kernel/NativePointerCapture.cs" }
.ToDictionary(path => path, path => Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(Path.Combine(root,path))))) };
string json = JsonSerializer.Serialize(result, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(Path.Combine(output, "Result.json"), json); Console.WriteLine(json);
}
private static double Time(Action action) { var timer = Stopwatch.StartNew(); action(); return timer.Elapsed.TotalMilliseconds; }
private static string Hash(int[] pixels) => Convert.ToHexStringLower(SHA256.HashData(System.Runtime.InteropServices.MemoryMarshal.AsBytes(pixels.AsSpan())));
private static int[] Pixels(object target) => (int[])target.GetType().GetField("pixels", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(target)!;
private static object CheckEditorPreparationHandoff(string root)
{
var prepared = (CanvasAdapter)Create(typeof(CanvasAdapter), root);
var main = (CanvasAdapter)Create(typeof(CanvasAdapter), root);
var cold = (CanvasAdapter)Create(typeof(CanvasAdapter), root);
var mismatch = (CanvasAdapter)Create(typeof(CanvasAdapter), root);
void Set(CanvasAdapter target, string name, object value) => typeof(CanvasAdapter).GetField(name, BindingFlags.NonPublic | BindingFlags.Instance)!.SetValue(target, value);
int Count(CanvasAdapter target, string name) => ((System.Collections.IDictionary)typeof(CanvasAdapter).GetField(name, BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(target)!).Count;
Set(prepared, "preparationOnly", true); Set(mismatch, "scale", 1);
Array.Fill(Pixels(prepared), -123); Array.Fill(Pixels(main), -123);
string preparedPixels = Hash(Pixels(prepared)), mainPixels = Hash(Pixels(main));
var samples = new[] { (Text: "using System; public class XFE { int value = 42; }", Family: "Consolas", Weight: 400),
(Text: "中文 C# Preview", Family: "system-ui", Weight: 700), (Text: "\uf475\uf30a", Family: "bootstrap-icons", Weight: 400) };
foreach (var sample in samples)
{
prepared.MeasureWebText(sample.Text, 13, sample.Family, sample.Weight);
prepared.PrepareEditorText(sample.Text, 13, sample.Family, sample.Weight);
prepared.RasterizeWebText(sample.Text, 13, sample.Family, sample.Weight);
}
prepared.MeasureWebText("中文", 13, "system-ui", 400);
main.MeasureWebText("中文", 13, "system-ui", 400);
object CjkFont(CanvasAdapter value)
{
var fonts = (System.Collections.IDictionary)typeof(CanvasAdapter).GetField("webFonts", BindingFlags.NonPublic | BindingFlags.Instance)!.GetValue(value)!;
object face = fonts[10]!;
return face.GetType().GetProperty("Font")!.GetValue(face)!;
}
var preparedFont = (Cosmos.Kernel.System.Graphics.Fonts.TrueTypeFont)CjkFont(prepared);
var mainFont = (Cosmos.Kernel.System.Graphics.Fonts.TrueTypeFont)CjkFont(main);
if (ReferenceEquals(preparedFont, mainFont) || !ReferenceEquals(preparedFont.Data, mainFont.Data)) throw new Exception("Font resource bytes are duplicated or mutable font caches are shared.");
string resourceHash = Convert.ToHexStringLower(SHA256.HashData(preparedFont.Data));
prepared.PrepareEditorText("中文", 13, "system-ui", 400);
prepared.RasterizeWebText("中文", 13, "system-ui", 400);
main.RasterizeWebText("中文", 13, "system-ui", 400);
if (resourceHash != Convert.ToHexStringLower(SHA256.HashData(mainFont.Data))) throw new Exception("The pinned font parser/rasterizer mutated shared font resource bytes.");
int warmedGlyphs = Count(prepared, "webGlyphs");
if (warmedGlyphs == 0 || preparedPixels != Hash(Pixels(prepared)) || mainPixels != Hash(Pixels(main))) throw new Exception("Editor preparation did not warm real glyphs without touching pixels.");
if (prepared.TryCompleteEditorPreparationHandoff(mismatch) || main.TryCompleteEditorPreparationHandoff(prepared) || prepared.TryCompleteEditorPreparationHandoff(prepared)) throw new Exception("Editor handoff accepted an incompatible canvas.");
if (!prepared.TryCompleteEditorPreparationHandoff(main) || !prepared.TryCompleteEditorPreparationHandoff(main) || prepared.TryCompleteEditorPreparationHandoff(cold)) throw new Exception("Editor handoff was not exclusive and idempotent.");
if (warmedGlyphs != Count(main, "webGlyphs") || preparedPixels != Hash(Pixels(prepared)) || mainPixels != Hash(Pixels(main))) throw new Exception("Editor handoff lost glyphs or changed pixels.");
Array.Clear(Pixels(main)); Array.Clear(Pixels(cold)); main.BeginScene(new(0, 0, 800, 450)); cold.BeginScene(new(0, 0, 800, 450));
long hitsBefore = main.WebTextMeasureCacheHits;
int glyphsBefore = Count(main, "webGlyphs"), y = 4;
foreach (var sample in samples)
{
if (main.MeasureWebText(sample.Text, 13, sample.Family, sample.Weight) != cold.MeasureWebText(sample.Text, 13, sample.Family, sample.Weight)) throw new Exception("Prepared metrics differ from the actual main canvas.");
main.WebText(sample.Text, 0xAC99EA, 4, y, 13, sample.Family, sample.Weight);
cold.WebText(sample.Text, 0xAC99EA, 4, y, 13, sample.Family, sample.Weight);
y += 24;
}
if (Hash(Pixels(main)) != Hash(Pixels(cold)) || glyphsBefore != Count(main, "webGlyphs") || main.WebTextMeasureCacheHits - hitsBefore < samples.Length) throw new Exception("Prepared native glyph handoff changed pixels or missed the scanout glyph cache.");
bool rejectedAfterHandoff = false;
try { prepared.PrepareEditorText("not owned by worker", 13, "Consolas", 400); } catch (InvalidOperationException) { rejectedAfterHandoff = true; }
if (!rejectedAfterHandoff) throw new Exception("Worker preparation remained available after ownership transfer.");
var mask = main.RasterizeWebText(samples[0].Text, 13, "Consolas", 400); string maskHash = Convert.ToHexStringLower(SHA256.HashData(mask.Alpha)); mask.Alpha.AsSpan().Clear();
if (maskHash != Convert.ToHexStringLower(SHA256.HashData(main.RasterizeWebText(samples[0].Text, 13, "Consolas", 400).Alpha))) throw new Exception("A writable caller corrupted a transferred mask.");
return new { Passed = true, ActualTrueTypeFonts = true, ScalePercent = 200, CssFontSize = 13, NativeGlyphSize = 26,
PreparedNativeGlyphs = warmedGlyphs, ExactColdRasterPixels = true, NoGlyphRasterizationAfterHandoff = true,
PreparationAndHandoffDoNotWritePixels = true, IncompatibleTargetRejected = true, ExclusiveAndIdempotent = true,
WorkerPreparationRejectedAfterHandoff = true, WritableMaskIsolated = true,
SharedImmutableCjkBytes = preparedFont.Data.Length, SharedFontResourceHashUnchanged = true,
IndependentMutableTrueTypeFontObjects = true };
}
private static object CheckNativeFrameCache(string root)
{
var native = (CanvasAdapter)Create(typeof(CanvasAdapter), root); var pixels = Pixels(native);
for (int i = 0; i < pixels.Length; i++) pixels[i] = unchecked(i * 123457);
var original = (int[])pixels.Clone(); var bounds = new DesktopBounds(10, 20, 30, 25);
native.BeginScene(bounds); native.StoreWebFrame(9, 10, 11, bounds, 0, .25);
Array.Fill(pixels, -123); var damage = new DesktopBounds(21, 27, 2, 3); native.BeginScene(damage);
if (native.WebPaintClip != damage || !native.TryRestoreWebFrame(9, 10, 11, bounds, 0, .25)) throw new Exception("Native damage restore missed.");
for (int y = 0; y < 900; y++) for (int x = 0; x < 1600; x++)
if (pixels[y * 1600 + x] != (x >= 42 && x < 46 && y >= 54 && y < 60 ? original[y * 1600 + x] : -123)) throw new Exception("Native damage restore touched incorrect pixels.");
Array.Fill(pixels, -123); var moved = bounds with { X = 30, Y = 30 }; native.BeginScene(moved);
if (!native.TryRestoreWebFrame(9, 10, 11, moved, 0, .25)) throw new Exception("Window movement invalidated native frame.");
for (int y = 0; y < 900; y++) for (int x = 0; x < 1600; x++)
if (pixels[y * 1600 + x] != (x >= 60 && x < 120 && y >= 60 && y < 110 ? original[(y - 20) * 1600 + x - 40] : -123)) throw new Exception("Native moved restore pixels changed.");
native.BeginScene(damage); native.StoreWebFrame(9, 12, 11, moved, 0, .25);
if (native.TryRestoreWebFrame(9, 12, 11, moved, 0, .25) || native.TryRestoreWebFrame(9, 10, 12, moved, 0, .25) ||
native.TryRestoreWebFrame(9, 10, 11, moved, 0, .5)) throw new Exception("Native stale/partial cache frame was accepted.");
if(native.CachedWebFrameCount != 1 || native.CachedWebFrameBytes != 12000 || native.WebFramePixelsRestored != 3024) throw new Exception("Native cache accounting changed.");
return new { Passed = true, DamagePixelsExact = true, MovedPixelsExact = true, PartialCaptureRejected = true,
RevisionLayoutScrollMissesVerified = true, native.CachedWebFrameCount, native.CachedWebFrameBytes, native.WebFrameRestoreHits, native.WebFramePixelsRestored };
}
private static object CheckNativeRenderYield(string root)
{
NativeKeyboardCapture.Prepare();while(NativeKeyboardCapture.TryRead(out _,out _,out _)){ }
NativePointerCapture.Prepare();while(NativePointerCapture.TryRead(out _)){ }
NativePointerCapture.Observe(0,0,false,false,false,0,0);while(NativePointerCapture.TryRead(out _)){ }
var native=(CanvasAdapter)Create(typeof(CanvasAdapter),root);var pixels=Pixels(native);Array.Fill(pixels,-123);
native.BeginScene(new(0,0,800,450));NativeKeyboardCapture.Observe(0x5B,false);bool yielded=false;
try{native.BlendCoverage(0xFFFFFF,0,0,1,4,new byte[]{255,255,255,255});}catch(DesktopRenderYieldException){yielded=true;}
if(!yielded||pixels.Any(value=>value!=-123)||!NativeKeyboardCapture.HasPendingReports)throw new Exception("Native keyboard render yield consumed input or changed a row.");
if(!NativeKeyboardCapture.TryRead(out var scan,out var released,out var lost)||scan!=0x5B||released||lost)throw new Exception("Native keyboard yield altered raw report.");
NativePointerCapture.Observe(20,30,false,false,false,0,1);
if(native.RenderYieldRequested)throw new Exception("Ordinary pointer motion cancelled native paint.");
native.BlendCoverage(0xFFFFFF,0,0,1,1,new byte[]{255});
if(!NativePointerCapture.TryRead(out var motion)||motion.X!=20||motion.Y!=30)throw new Exception("Native paint consumed motion.");
NativePointerCapture.Observe(20,30,true,false,false,0,2);yielded=false;
try{native.BlendCoverage(0xFFFFFF,0,1,1,1,new byte[]{255});}catch(DesktopRenderYieldException){yielded=true;}
if(!yielded||pixels[1600]!=-123||native.FramesPresented!=0||native.CachedWebFrameCount!=0)throw new Exception("Cancelled native row was cached/presented or painted.");
if(!NativePointerCapture.TryRead(out var down)||!down.LeftButton)throw new Exception("Native render yield consumed the button make.");
NativePointerCapture.Observe(20,30,false,false,false,0,3);while(NativePointerCapture.TryRead(out _)){ }
return new{Passed=true,KeyboardAndButtonYield=true,PendingReportsNotConsumed=true,OrdinaryMotionPaints=true,
CancelledRowUnmodified=true,CancelledFrameNotCachedOrPresented=true};
}
private static object CheckNativeAbortAndCoverage(string root)
{
var native=(CanvasAdapter)Create(typeof(CanvasAdapter),root);
var area=new DesktopBounds(4,3,12,5);
native.BeginScene(new(0,0,800,450));native.PreserveTranslatedSceneRegion(area,area.X,area.Y,true);native.EndScenePreservation();
long PendingPixels()
{
object rectangle=typeof(CanvasAdapter).GetField("unchangedScanout",BindingFlags.NonPublic|BindingFlags.Instance)!.GetValue(native)!;
return (long)(int)rectangle.GetType().GetProperty("Width")!.GetValue(rectangle)!*(int)rectangle.GetType().GetProperty("Height")!.GetValue(rectangle)!;
}
long normalPending=PendingPixels();if(normalPending!=240)throw new Exception("Normal scene end lost the valid scanout optimization.");
native.AbortScenePreservation();native.BeginScene(new(0,0,800,450));
if(PendingPixels()!=0)throw new Exception("Cancelled frame retained a stale scanout copy exclusion.");
var comparisons=new List<object>();var baseline=(BaselineCanvasAdapter)Create(typeof(BaselineCanvasAdapter),root);
int[] old=Pixels(baseline),current=Pixels(native);var random=new Random(74071);
for(int test=0;test<6;test++)
{
for(int i=0;i<old.Length;i++)old[i]=current[i]=random.Next();
baseline.BeginScene(new(0,0,800,450));native.BeginScene(new(0,0,800,450));
if((test&1)!=0)
{
baseline.SaveScene();native.SaveScene();baseline.PreserveTranslatedSceneRegion(area,8,4);native.PreserveTranslatedSceneRegion(area,8,4);
}
const int width=157,height=33;var mask=new byte[width*height];
for(int i=0;i<mask.Length;i++)mask[i]=test/2==0?(byte)255:test/2==1?(byte)0:i%64<8?(byte)0:i%64<40?(byte)255:(byte)(1+i%254);
baseline.BlendCoverage(0x8A72D5,-11,-3,width,height,mask);native.BlendCoverage(0x8A72D5,-11,-3,width,height,mask);
if(!old.AsSpan().SequenceEqual(current))throw new Exception("Native zero/opaque/mixed coverage changed clipped or motion-preserved pixels.");
comparisons.Add(new{Case=test,MotionPreserved=(test&1)!=0,AlphaMode=test/2==0?"Opaque":test/2==1?"Transparent":"Mixed",PixelsSha256=Hash(current),ExactPixels=true});
}
baseline.EndScenePreservation();native.EndScenePreservation();
var opaque=new byte[1280*720];Array.Fill(opaque,(byte)255);const int iterations=16;
double oldTime=Time(()=>{for(int i=0;i<iterations;i++)baseline.BlendCoverage(0x8A72D5,0,0,1280,720,opaque);})/iterations;
double newTime=Time(()=>{for(int i=0;i<iterations;i++)native.BlendCoverage(0x8A72D5,0,0,1280,720,opaque);})/iterations;
if(!old.AsSpan().SequenceEqual(current))throw new Exception("Native opaque benchmark changed pixels.");
return new{Passed=true,NormalEndKeepsScanoutSkipPixels=normalPending,AbortClearsScanoutSkipPixels=PendingPixels(),
CoverageComparisons=comparisons,BaselineOpaqueMilliseconds=oldTime,CurrentOpaqueMilliseconds=newTime,OpaqueSpeedup=oldTime/newTime,
HostOnly=true,NativeFrameAcceptance=false};
}
private static object CheckNativeMotionFrameCache(string root)
{
var native=(CanvasAdapter)Create(typeof(CanvasAdapter),root);var pixels=Pixels(native);
const int blue=unchecked((int)0xff0000ff),red=unchecked((int)0xffef3344);
Array.Fill(pixels,blue);var viewport=new DesktopBounds(0,0,40,30);native.BeginScene(new(0,0,800,450));
native.StoreWebFrame(1,1,1,viewport,0,0);
for(int y=6;y<16;y++)for(int x=8;x<32;x++)pixels[y*1600+x]=red;
native.SaveScene();native.PreserveTranslatedSceneRegion(new(4,3,12,5),6,4);
if(!native.TryRestoreWebFrame(1,1,1,viewport,0,0))throw new Exception("Protected background cache missed.");
for(int y=0;y<60;y++)for(int x=0;x<80;x++)
if(pixels[y*1600+x]!=(x>=12&&x<36&&y>=8&&y<18?red:blue))throw new Exception("Background frame cache overwrote a moved foreground window.");
if(native.WebFramePixelsRestored!=4560)throw new Exception("Protected motion pixels were counted as actual restored pixels.");
native.Fill(0x0000ff,0,0,40,30);native.StoreWebFrame(2,1,1,viewport,0,0);
if(native.WebFrameCaptures!=1)throw new Exception("Protected foreground pixels were captured as a background browser frame.");
native.AbortScenePreservation();native.BeginScene(new(0,0,800,450));Array.Fill(pixels,0);
if(native.TryRestoreWebFrame(2,1,1,viewport,0,0))throw new Exception("A partly obscured viewport was cached.");
if(!native.TryRestoreWebFrame(1,1,1,viewport,0,0))throw new Exception("Rejected motion capture evicted the good frame.");
for(int y=0;y<60;y++)for(int x=0;x<80;x++)if(pixels[y*1600+x]!=blue)throw new Exception("Good browser frame contains foreground pixels.");
return new{Passed=true,ForegroundPreservedPixels=240,ActualRestoredPixelsBeforeAbort=4560,
BackgroundCaptureRejected=true,GoodFramePreserved=true,ActualRestoredPixelsTotal=native.WebFramePixelsRestored,
Captures=native.WebFrameCaptures,HostOnly=true,NativeFrameAcceptance=false};
}
private static object Create(Type type, string root)
{
// Avoid firmware/HAL initialization on the host. Only the backing canvas,
// font dictionaries and clipping state used by the real painter are set.
object target = RuntimeHelpers.GetUninitializedObject(type);
const int width = 1600, height = 900;
var surface = new Canvas(width, height); int[] pixels = surface.GetBuffer()!; var scene = new int[pixels.Length];
void Set(string name, object value) => type.GetField(name, BindingFlags.NonPublic | BindingFlags.Instance)!.SetValue(target, value);
foreach (var field in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(Dictionary<,>)) field.SetValue(target, Activator.CreateInstance(field.FieldType));
else if(field.FieldType == typeof(DesktopWebFrameCache)) field.SetValue(target,new DesktopWebFrameCache());
}
Set("canvas", surface); Set("scale", 2); Set("pixels", pixels); Set("scene", scene);
Set("motion", new DesktopSceneMotionBuffer(pixels, scene, width, height));
Set("unicode", File.ReadAllBytes(Path.Combine(root, "assets/branding/console/xfe-unicode.bin")));
var clip = type.GetField("clip", BindingFlags.NonPublic | BindingFlags.Instance)!;
clip.SetValue(target, Activator.CreateInstance(clip.FieldType, 0, 0, width, height));
var clips = type.GetField("webClips", BindingFlags.NonPublic | BindingFlags.Instance)!;
clips.SetValue(target, Activator.CreateInstance(clips.FieldType));
return target;
}
}