using System.Globalization;
namespace XFESystem.Desktop;
/// <summary>Optional readback of the real presented framebuffer, in native pixels.</summary>
public interface IDesktopPresentedPixelsCanvas
{
long FramesPresented { get; }
long LastPresentTicks => 0;
bool TryFingerprintPresentedPixels(DesktopBounds nativeBounds, out DesktopPresentedPixelsFingerprint result);
}
public readonly record struct DesktopPresentedPixelsFingerprint(DesktopBounds NativeBounds, long PresentationSequence, string Fingerprint);
/// <summary>Bounded diagnostic fingerprint; never a substitute for GPU or screenshot evidence.</summary>
public static class DesktopPresentedPixels
{
public const int MaximumFingerprintPixels = 262_144;
public const string FingerprintAlgorithm = "RGB24-FNV1a64";
public static bool TryFingerprint(ReadOnlySpan<int> framebuffer, int width, int height, int stride,
DesktopBounds bounds, long presentationSequence, out DesktopPresentedPixelsFingerprint result)
{
result = default;
if (presentationSequence <= 0 || width <= 0 || height <= 0 || stride < width || bounds.X < 0 || bounds.Y < 0 ||
bounds.Width <= 0 || bounds.Height <= 0 || (long)bounds.X + bounds.Width > width || (long)bounds.Y + bounds.Height > height ||
(long)bounds.Width * bounds.Height > MaximumFingerprintPixels || (long)(height - 1) * stride + width > framebuffer.Length)
return false;
ulong hash = 14695981039346656037;
for (int y = bounds.Y; y < bounds.Y + bounds.Height; y++)
for (int x = bounds.X; x < bounds.X + bounds.Width; x++)
{
uint pixel = unchecked((uint)framebuffer[y * stride + x]);
hash = unchecked((hash ^ (byte)(pixel >> 16)) * 1099511628211);
hash = unchecked((hash ^ (byte)(pixel >> 8)) * 1099511628211);
hash = unchecked((hash ^ (byte)pixel) * 1099511628211);
}
result = new(bounds, presentationSequence, hash.ToString("x16", CultureInfo.InvariantCulture));
return true;
}
}
using System.Globalization;
namespace XFESystem.Desktop;
/// <summary>Optional readback of the real presented framebuffer, in native pixels.</summary>
public interface IDesktopPresentedPixelsCanvas
{
long FramesPresented { get; }
long LastPresentTicks => 0;
bool TryFingerprintPresentedPixels(DesktopBounds nativeBounds, out DesktopPresentedPixelsFingerprint result);
}
public readonly record struct DesktopPresentedPixelsFingerprint(DesktopBounds NativeBounds, long PresentationSequence, string Fingerprint);
/// <summary>Bounded diagnostic fingerprint; never a substitute for GPU or screenshot evidence.</summary>
public static class DesktopPresentedPixels
{
public const int MaximumFingerprintPixels = 262_144;
public const string FingerprintAlgorithm = "RGB24-FNV1a64";
public static bool TryFingerprint(ReadOnlySpan<int> framebuffer, int width, int height, int stride,
DesktopBounds bounds, long presentationSequence, out DesktopPresentedPixelsFingerprint result)
{
result = default;
if (presentationSequence <= 0 || width <= 0 || height <= 0 || stride < width || bounds.X < 0 || bounds.Y < 0 ||
bounds.Width <= 0 || bounds.Height <= 0 || (long)bounds.X + bounds.Width > width || (long)bounds.Y + bounds.Height > height ||
(long)bounds.Width * bounds.Height > MaximumFingerprintPixels || (long)(height - 1) * stride + width > framebuffer.Length)
return false;
ulong hash = 14695981039346656037;
for (int y = bounds.Y; y < bounds.Y + bounds.Height; y++)
for (int x = bounds.X; x < bounds.X + bounds.Width; x++)
{
uint pixel = unchecked((uint)framebuffer[y * stride + x]);
hash = unchecked((hash ^ (byte)(pixel >> 16)) * 1099511628211);
hash = unchecked((hash ^ (byte)(pixel >> 8)) * 1099511628211);
hash = unchecked((hash ^ (byte)pixel) * 1099511628211);
}
result = new(bounds, presentationSequence, hash.ToString("x16", CultureInfo.InvariantCulture));
return true;
}
}