diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs
index b1bacc6483..d5e5cb14dc 100644
--- a/samples/ControlCatalog.NetCore/Program.cs
+++ b/samples/ControlCatalog.NetCore/Program.cs
@@ -99,6 +99,15 @@ namespace ControlCatalog.NetCore
SilenceConsole();
return builder.StartLinuxDrm(args, scaling: GetScaling());
}
+ else if (args.Contains("--dxgi"))
+ {
+ builder.With(new Win32PlatformOptions()
+ {
+ UseLowLatencyDxgiSwapChain = true,
+ UseWindowsUIComposition = false
+ });
+ return builder.StartWithClassicDesktopLifetime(args);
+ }
else
return builder.StartWithClassicDesktopLifetime(args);
}
diff --git a/samples/ControlCatalog.NetCore/Properties/launchSettings.json b/samples/ControlCatalog.NetCore/Properties/launchSettings.json
new file mode 100644
index 0000000000..5964ca320e
--- /dev/null
+++ b/samples/ControlCatalog.NetCore/Properties/launchSettings.json
@@ -0,0 +1,11 @@
+{
+ "profiles": {
+ "ControlCatalog.NetCore": {
+ "commandName": "Project"
+ },
+ "Dxgi": {
+ "commandName": "Project",
+ "commandLineArgs": "--dxgi"
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index 6b550a30be..18f0dd16ba 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -33,4 +33,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Converter/DegToRadConverter.cs b/samples/ControlCatalog/Converter/DegToRadConverter.cs
new file mode 100644
index 0000000000..b062bcb64a
--- /dev/null
+++ b/samples/ControlCatalog/Converter/DegToRadConverter.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using Avalonia.Data.Converters;
+
+namespace ControlCatalog.Converter
+{
+ public class DegToRadConverter : IValueConverter
+ {
+ public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (value is double rad)
+ {
+ return rad * 180.0d / Math.PI;
+ }
+ return 0.0d;
+ }
+
+ public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (value is double deg)
+ {
+ return deg / 180.0d * Math.PI;
+ }
+ return 0.0d;
+ }
+ }
+}
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index b5a09b5fbd..b95b455ca4 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -66,6 +66,9 @@
+
+
+
diff --git a/samples/ControlCatalog/Pages/CustomDrawing.xaml b/samples/ControlCatalog/Pages/CustomDrawing.xaml
new file mode 100644
index 0000000000..04b7fcfea5
--- /dev/null
+++ b/samples/ControlCatalog/Pages/CustomDrawing.xaml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/CustomDrawing.xaml.cs b/samples/ControlCatalog/Pages/CustomDrawing.xaml.cs
new file mode 100644
index 0000000000..0416e587b9
--- /dev/null
+++ b/samples/ControlCatalog/Pages/CustomDrawing.xaml.cs
@@ -0,0 +1,67 @@
+using System;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+ public partial class CustomDrawing : UserControl
+ {
+ public CustomDrawing()
+ {
+ InitializeComponent();
+ }
+
+ private CustomDrawingExampleControl? _customControl;
+ public CustomDrawingExampleControl CustomDrawingControl
+ {
+ get
+ {
+ if (_customControl is not null)
+ return _customControl;
+ throw new System.Exception("Control did not get initialized");
+ }
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ var cntrl = this.FindControl("CustomDrawingControl");
+ if (cntrl != null)
+ {
+ _customControl = cntrl;
+ }
+ else
+ {
+ // be sad about it
+ }
+ }
+
+ private void RotateMinus (object? sender, RoutedEventArgs e)
+ {
+ if (_customControl is null) return;
+ _customControl.Rotation -= Math.PI / 20.0d;
+ }
+
+ private void RotatePlus(object? sender, RoutedEventArgs e)
+ {
+ if (_customControl is null)
+ return;
+ _customControl.Rotation += Math.PI / 20.0d;
+ }
+
+ private void ZoomIn(object? sender, RoutedEventArgs e)
+ {
+ if (_customControl is null)
+ return;
+ _customControl.Scale *= 1.2d;
+ }
+
+ private void ZoomOut(object? sender, RoutedEventArgs e)
+ {
+ if (_customControl is null)
+ return;
+ _customControl.Scale /= 1.2d;
+ }
+ }
+}
diff --git a/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs b/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
new file mode 100644
index 0000000000..11e5e32cf1
--- /dev/null
+++ b/samples/ControlCatalog/Pages/CustomDrawingExampleControl.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Media;
+using Avalonia.Input;
+using Avalonia.Threading;
+using Avalonia.Controls.Shapes;
+
+namespace ControlCatalog.Pages
+{
+ public class CustomDrawingExampleControl : Control
+ {
+ private Point _cursorPoint;
+
+
+ public StyledProperty ScaleProperty = AvaloniaProperty.Register(nameof(Scale), 1.0d);
+ public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
+
+ public StyledProperty RotationProperty = AvaloniaProperty.Register(nameof(Rotation));
+ ///
+ /// Rotation, measured in Radians!
+ ///
+ public double Rotation
+ {
+ get => GetValue(RotationProperty);
+ set
+ {
+ double valueToUse = value % (Math.PI * 2);
+ SetValue(RotationProperty, valueToUse);
+ }
+ }
+
+ public StyledProperty ViewportCenterYProperty = AvaloniaProperty.Register(nameof(ViewportCenterY), 0.0d);
+ public double ViewportCenterY { get => GetValue(ViewportCenterYProperty); set => SetValue(ViewportCenterYProperty, value); }
+
+ public StyledProperty ViewportCenterXProperty = AvaloniaProperty.Register(nameof(ViewportCenterX), 0.0d);
+ public double ViewportCenterX { get => GetValue(ViewportCenterXProperty); set => SetValue(ViewportCenterXProperty, value); }
+
+ private IPen _pen;
+
+ private System.Diagnostics.Stopwatch _timeKeeper = System.Diagnostics.Stopwatch.StartNew();
+
+ private bool _isPointerCaptured = false;
+
+ public CustomDrawingExampleControl()
+ {
+ _pen = new Pen(new SolidColorBrush(Colors.Black), lineCap: PenLineCap.Round);
+
+ var _arc = new ArcSegment()
+ {
+ IsLargeArc = false,
+ Point = new Point(0, 0),
+ RotationAngle = 0,
+ Size = new Size(25, 25),
+ SweepDirection = SweepDirection.Clockwise,
+
+ };
+ StreamGeometry sg = new StreamGeometry();
+ var cntx = sg.Open();
+ cntx.BeginFigure(new Point(-25.0d, -10.0d), false);
+ cntx.ArcTo(new Point(25.0d, -10.0d), new Size(10.0d, 10.0d), 0.0d, false, SweepDirection.Clockwise);
+ cntx.EndFigure(true);
+ _smileGeometry = sg.Clone();
+ }
+
+ private Geometry _smileGeometry;
+
+ protected override void OnPointerMoved(PointerEventArgs e)
+ {
+ base.OnPointerMoved(e);
+
+ Point previousPoint = _cursorPoint;
+
+ _cursorPoint = e.GetPosition(this);
+
+ if (_isPointerCaptured)
+ {
+ Point oldWorldPoint = UIPointToWorldPoint(previousPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
+ Point newWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
+
+ Vector diff = newWorldPoint - oldWorldPoint;
+
+ ViewportCenterX -= diff.X;
+ ViewportCenterY -= diff.Y;
+ }
+ }
+
+ protected override void OnPointerPressed(PointerPressedEventArgs e)
+ {
+ e.Handled = true;
+ e.Pointer.Capture(this);
+ _isPointerCaptured = true;
+ base.OnPointerPressed(e);
+ }
+
+ protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
+ {
+ base.OnPointerWheelChanged(e);
+ var oldScale = Scale;
+ Scale *= (1.0d + e.Delta.Y / 12.0d);
+
+ Point oldWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, oldScale, Rotation);
+ Point newWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
+
+ Vector diff = newWorldPoint - oldWorldPoint;
+
+ ViewportCenterX -= diff.X;
+ ViewportCenterY -= diff.Y;
+ }
+
+ protected override void OnPointerReleased(PointerReleasedEventArgs e)
+ {
+ e.Pointer.Capture(null);
+ _isPointerCaptured = false;
+ base.OnPointerReleased(e);
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ var localBounds = new Rect(new Size(this.Bounds.Width, this.Bounds.Height));
+ var clip = context.PushClip(this.Bounds);
+ context.DrawRectangle(Brushes.White, _pen, localBounds, 1.0d);
+
+ var halfMax = Math.Max(this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d) * Math.Sqrt(2.0d);
+ var halfMin = Math.Min(this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d) / 1.3d;
+ var halfWidth = this.Bounds.Width / 2.0d;
+ var halfHeight = this.Bounds.Height / 2.0d;
+
+ // 0,0 refers to the top-left of the control now. It is not prime time to draw gui stuff because it'll be under the world
+
+ var translateModifier = context.PushPreTransform(Avalonia.Matrix.CreateTranslation(new Avalonia.Vector(halfWidth, halfHeight)));
+
+ // now 0,0 refers to the ViewportCenter(X,Y).
+ var rotationMatrix = Avalonia.Matrix.CreateRotation(Rotation);
+ var rotationModifier = context.PushPreTransform(rotationMatrix);
+
+ // everything is rotated but not scaled
+
+ var scaleModifier = context.PushPreTransform(Avalonia.Matrix.CreateScale(Scale, -Scale));
+
+ var mapPositionModifier = context.PushPreTransform(Matrix.CreateTranslation(new Vector(-ViewportCenterX, -ViewportCenterY)));
+
+ // now everything is rotated and scaled, and at the right position, now we're drawing strictly in world coordinates
+
+ context.DrawEllipse(Brushes.White, _pen, new Point(0.0d, 0.0d), 50.0d, 50.0d);
+ context.DrawLine(_pen, new Point(-25.0d, -5.0d), new Point(-25.0d, 15.0d));
+ context.DrawLine(_pen, new Point(25.0d, -5.0d), new Point(25.0d, 15.0d));
+ context.DrawGeometry(null, _pen, _smileGeometry);
+
+ Point cursorInWorldPoint = UIPointToWorldPoint(_cursorPoint, ViewportCenterX, ViewportCenterY, Scale, Rotation);
+ context.DrawEllipse(Brushes.Gray, _pen, cursorInWorldPoint, 20.0d, 20.0d);
+
+
+ for (int i = 0; i < 10; i++)
+ {
+ double orbitRadius = i * 100 + 200;
+ var orbitInput = ((_timeKeeper.Elapsed.TotalMilliseconds + 987654d) / orbitRadius) / 10.0d;
+ if (i % 3 == 0)
+ orbitInput *= -1;
+ Point orbitPosition = new Point(Math.Sin(orbitInput) * orbitRadius, Math.Cos(orbitInput) * orbitRadius);
+ context.DrawEllipse(Brushes.Gray, _pen, orbitPosition, 20.0d, 20.0d);
+ }
+
+
+ // end drawing the world
+
+ mapPositionModifier.Dispose();
+
+ scaleModifier.Dispose();
+
+ rotationModifier.Dispose();
+ translateModifier.Dispose();
+
+ // this is prime time to draw gui stuff
+
+ context.DrawLine(_pen, _cursorPoint + new Vector(-20, 0), _cursorPoint + new Vector(20, 0));
+ context.DrawLine(_pen, _cursorPoint + new Vector(0, -20), _cursorPoint + new Vector(0, 20));
+
+ clip.Dispose();
+
+ // oh and draw again when you can, no rush, right?
+ Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
+ }
+
+ private Point UIPointToWorldPoint(Point inPoint, double viewportCenterX, double viewportCenterY, double scale, double rotation)
+ {
+ Point workingPoint = new Point(inPoint.X, -inPoint.Y);
+ workingPoint += new Vector(-this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d);
+ workingPoint /= scale;
+
+ workingPoint = Matrix.CreateRotation(rotation).Transform(workingPoint);
+
+ workingPoint += new Vector(viewportCenterX, viewportCenterY);
+
+ return workingPoint;
+ }
+
+ private Point WorldPointToUIPoint(Point inPoint, double viewportCenterX, double viewportCenterY, double scale, double rotation)
+ {
+ Point workingPoint = new Point(inPoint.X, inPoint.Y);
+
+ workingPoint -= new Vector(viewportCenterX, viewportCenterY);
+ // undo rotation
+ workingPoint = Matrix.CreateRotation(-rotation).Transform(workingPoint);
+ workingPoint *= scale;
+ workingPoint -= new Vector(-this.Bounds.Width / 2.0d, this.Bounds.Height / 2.0d);
+ workingPoint = new Point(workingPoint.X, -workingPoint.Y);
+
+ return workingPoint;
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
index 308e22b4e2..00ce309519 100644
--- a/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
+++ b/src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
@@ -14,6 +14,7 @@
+
diff --git a/src/Windows/Avalonia.Win32/DirectX/DirectXEnums.cs b/src/Windows/Avalonia.Win32/DirectX/DirectXEnums.cs
new file mode 100644
index 0000000000..3a67da530f
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DirectX/DirectXEnums.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Win32.DxgiSwapchain
+{
+ internal enum D3D_FEATURE_LEVEL
+ {
+ D3D_FEATURE_LEVEL_1_0_CORE = 0x1000,
+
+ D3D_FEATURE_LEVEL_9_1 = 0x9100,
+
+ D3D_FEATURE_LEVEL_9_2 = 0x9200,
+
+ D3D_FEATURE_LEVEL_9_3 = 0x9300,
+
+ D3D_FEATURE_LEVEL_10_0 = 0xa000,
+
+ D3D_FEATURE_LEVEL_10_1 = 0xa100,
+
+ D3D_FEATURE_LEVEL_11_0 = 0xb000,
+
+ D3D_FEATURE_LEVEL_11_1 = 0xb100,
+
+ D3D_FEATURE_LEVEL_12_0 = 0xc000,
+
+ D3D_FEATURE_LEVEL_12_1 = 0xc100,
+
+ D3D_FEATURE_LEVEL_12_2 = 0xc200,
+ }
+
+ internal enum D3D11_RESOURCE_DIMENSION
+ {
+ D3D11_USAGE_DEFAULT = 0,
+
+ D3D11_USAGE_IMMUTABLE = 1,
+
+ D3D11_USAGE_DYNAMIC = 2,
+
+ D3D11_USAGE_STAGING = 3,
+ }
+
+ internal enum D3D11_USAGE
+ {
+ D3D11_USAGE_DEFAULT = 0,
+
+ D3D11_USAGE_IMMUTABLE = 1,
+
+ D3D11_USAGE_DYNAMIC = 2,
+
+ D3D11_USAGE_STAGING = 3,
+ }
+ internal enum DXGI_SWAP_EFFECT
+ {
+ DXGI_SWAP_EFFECT_DISCARD = 0,
+
+ DXGI_SWAP_EFFECT_SEQUENTIAL = 1,
+
+ DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL = 3,
+
+ DXGI_SWAP_EFFECT_FLIP_DISCARD = 4,
+ }
+
+ [Flags]
+ internal enum DXGI_SWAP_CHAIN_FLAG
+ {
+ DXGI_SWAP_CHAIN_FLAG_NONPREROTATED = 1,
+
+ DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH = 2,
+
+ DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE = 4,
+
+ DXGI_SWAP_CHAIN_FLAG_RESTRICTED_CONTENT = 8,
+
+ DXGI_SWAP_CHAIN_FLAG_RESTRICT_SHARED_RESOURCE_DRIVER = 16,
+
+ DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY = 32,
+
+ DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT = 64,
+
+ DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER = 128,
+
+ DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO = 256,
+
+ DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO = 512,
+
+ DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED = 1024,
+
+ DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING = 2048,
+
+ DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS = 4096,
+ }
+
+ internal enum DXGI_SCALING
+ {
+ DXGI_SCALING_STRETCH = 0,
+
+ DXGI_SCALING_NONE = 1,
+
+ DXGI_SCALING_ASPECT_RATIO_STRETCH = 2,
+ }
+
+ internal enum DXGI_RESIDENCY
+ {
+ DXGI_RESIDENCY_FULLY_RESIDENT = 1,
+
+ DXGI_RESIDENCY_RESIDENT_IN_SHARED_MEMORY = 2,
+
+ DXGI_RESIDENCY_EVICTED_TO_DISK = 3,
+ }
+
+ internal enum DXGI_MODE_ROTATION
+ {
+ DXGI_MODE_ROTATION_UNSPECIFIED = 0,
+
+ DXGI_MODE_ROTATION_IDENTITY = 1,
+
+ DXGI_MODE_ROTATION_ROTATE90 = 2,
+
+ DXGI_MODE_ROTATION_ROTATE180 = 3,
+
+ DXGI_MODE_ROTATION_ROTATE270 = 4,
+ }
+
+ internal enum DXGI_ALPHA_MODE
+ {
+ DXGI_ALPHA_MODE_UNSPECIFIED = 0,
+
+ DXGI_ALPHA_MODE_PREMULTIPLIED = 1,
+
+ DXGI_ALPHA_MODE_STRAIGHT = 2,
+
+ DXGI_ALPHA_MODE_IGNORE = 3,
+
+ DXGI_ALPHA_MODE_FORCE_DWORD = (unchecked((int)0xffffffff)),
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs b/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs
new file mode 100644
index 0000000000..f059c18257
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DirectX/DirectXStructs.cs
@@ -0,0 +1,1370 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using static Avalonia.Win32.Interop.UnmanagedMethods;
+
+namespace Avalonia.Win32.DxgiSwapchain
+{
+#nullable enable
+ public unsafe struct HANDLE
+ {
+ public readonly void* Value;
+
+ public HANDLE(void* value)
+ {
+ Value = value;
+ }
+
+ public static HANDLE INVALID_VALUE => new HANDLE((void*)(-1));
+
+ public static HANDLE NULL => new HANDLE(null);
+
+ public static bool operator ==(HANDLE left, HANDLE right) => left.Value == right.Value;
+
+ public static bool operator !=(HANDLE left, HANDLE right) => left.Value != right.Value;
+
+ public override bool Equals(object? obj) => (obj is HANDLE other) && Equals(other);
+
+ public bool Equals(HANDLE other) => ((nuint)(Value)).Equals((nuint)(other.Value));
+
+ public override int GetHashCode() => ((nuint)(Value)).GetHashCode();
+
+ public override string ToString() => ((IntPtr)Value).ToString();
+ }
+
+ internal unsafe partial struct MONITORINFOEXW
+ {
+ internal MONITORINFO Base;
+
+ internal fixed ushort szDevice[32];
+ }
+
+ internal unsafe struct DXGI_GAMMA_CONTROL
+ {
+ public DXGI_RGB Scale;
+
+ public DXGI_RGB Offset;
+
+ public _GammaCurve_e__FixedBuffer GammaCurve;
+
+ public partial struct _GammaCurve_e__FixedBuffer
+ {
+ public DXGI_RGB e0;
+ public DXGI_RGB e1;
+ public DXGI_RGB e2;
+ public DXGI_RGB e3;
+ public DXGI_RGB e4;
+ public DXGI_RGB e5;
+ public DXGI_RGB e6;
+ public DXGI_RGB e7;
+ public DXGI_RGB e8;
+ public DXGI_RGB e9;
+ public DXGI_RGB e10;
+ public DXGI_RGB e11;
+ public DXGI_RGB e12;
+ public DXGI_RGB e13;
+ public DXGI_RGB e14;
+ public DXGI_RGB e15;
+ public DXGI_RGB e16;
+ public DXGI_RGB e17;
+ public DXGI_RGB e18;
+ public DXGI_RGB e19;
+ public DXGI_RGB e20;
+ public DXGI_RGB e21;
+ public DXGI_RGB e22;
+ public DXGI_RGB e23;
+ public DXGI_RGB e24;
+ public DXGI_RGB e25;
+ public DXGI_RGB e26;
+ public DXGI_RGB e27;
+ public DXGI_RGB e28;
+ public DXGI_RGB e29;
+ public DXGI_RGB e30;
+ public DXGI_RGB e31;
+ public DXGI_RGB e32;
+ public DXGI_RGB e33;
+ public DXGI_RGB e34;
+ public DXGI_RGB e35;
+ public DXGI_RGB e36;
+ public DXGI_RGB e37;
+ public DXGI_RGB e38;
+ public DXGI_RGB e39;
+ public DXGI_RGB e40;
+ public DXGI_RGB e41;
+ public DXGI_RGB e42;
+ public DXGI_RGB e43;
+ public DXGI_RGB e44;
+ public DXGI_RGB e45;
+ public DXGI_RGB e46;
+ public DXGI_RGB e47;
+ public DXGI_RGB e48;
+ public DXGI_RGB e49;
+ public DXGI_RGB e50;
+ public DXGI_RGB e51;
+ public DXGI_RGB e52;
+ public DXGI_RGB e53;
+ public DXGI_RGB e54;
+ public DXGI_RGB e55;
+ public DXGI_RGB e56;
+ public DXGI_RGB e57;
+ public DXGI_RGB e58;
+ public DXGI_RGB e59;
+ public DXGI_RGB e60;
+ public DXGI_RGB e61;
+ public DXGI_RGB e62;
+ public DXGI_RGB e63;
+ public DXGI_RGB e64;
+ public DXGI_RGB e65;
+ public DXGI_RGB e66;
+ public DXGI_RGB e67;
+ public DXGI_RGB e68;
+ public DXGI_RGB e69;
+ public DXGI_RGB e70;
+ public DXGI_RGB e71;
+ public DXGI_RGB e72;
+ public DXGI_RGB e73;
+ public DXGI_RGB e74;
+ public DXGI_RGB e75;
+ public DXGI_RGB e76;
+ public DXGI_RGB e77;
+ public DXGI_RGB e78;
+ public DXGI_RGB e79;
+ public DXGI_RGB e80;
+ public DXGI_RGB e81;
+ public DXGI_RGB e82;
+ public DXGI_RGB e83;
+ public DXGI_RGB e84;
+ public DXGI_RGB e85;
+ public DXGI_RGB e86;
+ public DXGI_RGB e87;
+ public DXGI_RGB e88;
+ public DXGI_RGB e89;
+ public DXGI_RGB e90;
+ public DXGI_RGB e91;
+ public DXGI_RGB e92;
+ public DXGI_RGB e93;
+ public DXGI_RGB e94;
+ public DXGI_RGB e95;
+ public DXGI_RGB e96;
+ public DXGI_RGB e97;
+ public DXGI_RGB e98;
+ public DXGI_RGB e99;
+ public DXGI_RGB e100;
+ public DXGI_RGB e101;
+ public DXGI_RGB e102;
+ public DXGI_RGB e103;
+ public DXGI_RGB e104;
+ public DXGI_RGB e105;
+ public DXGI_RGB e106;
+ public DXGI_RGB e107;
+ public DXGI_RGB e108;
+ public DXGI_RGB e109;
+ public DXGI_RGB e110;
+ public DXGI_RGB e111;
+ public DXGI_RGB e112;
+ public DXGI_RGB e113;
+ public DXGI_RGB e114;
+ public DXGI_RGB e115;
+ public DXGI_RGB e116;
+ public DXGI_RGB e117;
+ public DXGI_RGB e118;
+ public DXGI_RGB e119;
+ public DXGI_RGB e120;
+ public DXGI_RGB e121;
+ public DXGI_RGB e122;
+ public DXGI_RGB e123;
+ public DXGI_RGB e124;
+ public DXGI_RGB e125;
+ public DXGI_RGB e126;
+ public DXGI_RGB e127;
+ public DXGI_RGB e128;
+ public DXGI_RGB e129;
+ public DXGI_RGB e130;
+ public DXGI_RGB e131;
+ public DXGI_RGB e132;
+ public DXGI_RGB e133;
+ public DXGI_RGB e134;
+ public DXGI_RGB e135;
+ public DXGI_RGB e136;
+ public DXGI_RGB e137;
+ public DXGI_RGB e138;
+ public DXGI_RGB e139;
+ public DXGI_RGB e140;
+ public DXGI_RGB e141;
+ public DXGI_RGB e142;
+ public DXGI_RGB e143;
+ public DXGI_RGB e144;
+ public DXGI_RGB e145;
+ public DXGI_RGB e146;
+ public DXGI_RGB e147;
+ public DXGI_RGB e148;
+ public DXGI_RGB e149;
+ public DXGI_RGB e150;
+ public DXGI_RGB e151;
+ public DXGI_RGB e152;
+ public DXGI_RGB e153;
+ public DXGI_RGB e154;
+ public DXGI_RGB e155;
+ public DXGI_RGB e156;
+ public DXGI_RGB e157;
+ public DXGI_RGB e158;
+ public DXGI_RGB e159;
+ public DXGI_RGB e160;
+ public DXGI_RGB e161;
+ public DXGI_RGB e162;
+ public DXGI_RGB e163;
+ public DXGI_RGB e164;
+ public DXGI_RGB e165;
+ public DXGI_RGB e166;
+ public DXGI_RGB e167;
+ public DXGI_RGB e168;
+ public DXGI_RGB e169;
+ public DXGI_RGB e170;
+ public DXGI_RGB e171;
+ public DXGI_RGB e172;
+ public DXGI_RGB e173;
+ public DXGI_RGB e174;
+ public DXGI_RGB e175;
+ public DXGI_RGB e176;
+ public DXGI_RGB e177;
+ public DXGI_RGB e178;
+ public DXGI_RGB e179;
+ public DXGI_RGB e180;
+ public DXGI_RGB e181;
+ public DXGI_RGB e182;
+ public DXGI_RGB e183;
+ public DXGI_RGB e184;
+ public DXGI_RGB e185;
+ public DXGI_RGB e186;
+ public DXGI_RGB e187;
+ public DXGI_RGB e188;
+ public DXGI_RGB e189;
+ public DXGI_RGB e190;
+ public DXGI_RGB e191;
+ public DXGI_RGB e192;
+ public DXGI_RGB e193;
+ public DXGI_RGB e194;
+ public DXGI_RGB e195;
+ public DXGI_RGB e196;
+ public DXGI_RGB e197;
+ public DXGI_RGB e198;
+ public DXGI_RGB e199;
+ public DXGI_RGB e200;
+ public DXGI_RGB e201;
+ public DXGI_RGB e202;
+ public DXGI_RGB e203;
+ public DXGI_RGB e204;
+ public DXGI_RGB e205;
+ public DXGI_RGB e206;
+ public DXGI_RGB e207;
+ public DXGI_RGB e208;
+ public DXGI_RGB e209;
+ public DXGI_RGB e210;
+ public DXGI_RGB e211;
+ public DXGI_RGB e212;
+ public DXGI_RGB e213;
+ public DXGI_RGB e214;
+ public DXGI_RGB e215;
+ public DXGI_RGB e216;
+ public DXGI_RGB e217;
+ public DXGI_RGB e218;
+ public DXGI_RGB e219;
+ public DXGI_RGB e220;
+ public DXGI_RGB e221;
+ public DXGI_RGB e222;
+ public DXGI_RGB e223;
+ public DXGI_RGB e224;
+ public DXGI_RGB e225;
+ public DXGI_RGB e226;
+ public DXGI_RGB e227;
+ public DXGI_RGB e228;
+ public DXGI_RGB e229;
+ public DXGI_RGB e230;
+ public DXGI_RGB e231;
+ public DXGI_RGB e232;
+ public DXGI_RGB e233;
+ public DXGI_RGB e234;
+ public DXGI_RGB e235;
+ public DXGI_RGB e236;
+ public DXGI_RGB e237;
+ public DXGI_RGB e238;
+ public DXGI_RGB e239;
+ public DXGI_RGB e240;
+ public DXGI_RGB e241;
+ public DXGI_RGB e242;
+ public DXGI_RGB e243;
+ public DXGI_RGB e244;
+ public DXGI_RGB e245;
+ public DXGI_RGB e246;
+ public DXGI_RGB e247;
+ public DXGI_RGB e248;
+ public DXGI_RGB e249;
+ public DXGI_RGB e250;
+ public DXGI_RGB e251;
+ public DXGI_RGB e252;
+ public DXGI_RGB e253;
+ public DXGI_RGB e254;
+ public DXGI_RGB e255;
+ public DXGI_RGB e256;
+ public DXGI_RGB e257;
+ public DXGI_RGB e258;
+ public DXGI_RGB e259;
+ public DXGI_RGB e260;
+ public DXGI_RGB e261;
+ public DXGI_RGB e262;
+ public DXGI_RGB e263;
+ public DXGI_RGB e264;
+ public DXGI_RGB e265;
+ public DXGI_RGB e266;
+ public DXGI_RGB e267;
+ public DXGI_RGB e268;
+ public DXGI_RGB e269;
+ public DXGI_RGB e270;
+ public DXGI_RGB e271;
+ public DXGI_RGB e272;
+ public DXGI_RGB e273;
+ public DXGI_RGB e274;
+ public DXGI_RGB e275;
+ public DXGI_RGB e276;
+ public DXGI_RGB e277;
+ public DXGI_RGB e278;
+ public DXGI_RGB e279;
+ public DXGI_RGB e280;
+ public DXGI_RGB e281;
+ public DXGI_RGB e282;
+ public DXGI_RGB e283;
+ public DXGI_RGB e284;
+ public DXGI_RGB e285;
+ public DXGI_RGB e286;
+ public DXGI_RGB e287;
+ public DXGI_RGB e288;
+ public DXGI_RGB e289;
+ public DXGI_RGB e290;
+ public DXGI_RGB e291;
+ public DXGI_RGB e292;
+ public DXGI_RGB e293;
+ public DXGI_RGB e294;
+ public DXGI_RGB e295;
+ public DXGI_RGB e296;
+ public DXGI_RGB e297;
+ public DXGI_RGB e298;
+ public DXGI_RGB e299;
+ public DXGI_RGB e300;
+ public DXGI_RGB e301;
+ public DXGI_RGB e302;
+ public DXGI_RGB e303;
+ public DXGI_RGB e304;
+ public DXGI_RGB e305;
+ public DXGI_RGB e306;
+ public DXGI_RGB e307;
+ public DXGI_RGB e308;
+ public DXGI_RGB e309;
+ public DXGI_RGB e310;
+ public DXGI_RGB e311;
+ public DXGI_RGB e312;
+ public DXGI_RGB e313;
+ public DXGI_RGB e314;
+ public DXGI_RGB e315;
+ public DXGI_RGB e316;
+ public DXGI_RGB e317;
+ public DXGI_RGB e318;
+ public DXGI_RGB e319;
+ public DXGI_RGB e320;
+ public DXGI_RGB e321;
+ public DXGI_RGB e322;
+ public DXGI_RGB e323;
+ public DXGI_RGB e324;
+ public DXGI_RGB e325;
+ public DXGI_RGB e326;
+ public DXGI_RGB e327;
+ public DXGI_RGB e328;
+ public DXGI_RGB e329;
+ public DXGI_RGB e330;
+ public DXGI_RGB e331;
+ public DXGI_RGB e332;
+ public DXGI_RGB e333;
+ public DXGI_RGB e334;
+ public DXGI_RGB e335;
+ public DXGI_RGB e336;
+ public DXGI_RGB e337;
+ public DXGI_RGB e338;
+ public DXGI_RGB e339;
+ public DXGI_RGB e340;
+ public DXGI_RGB e341;
+ public DXGI_RGB e342;
+ public DXGI_RGB e343;
+ public DXGI_RGB e344;
+ public DXGI_RGB e345;
+ public DXGI_RGB e346;
+ public DXGI_RGB e347;
+ public DXGI_RGB e348;
+ public DXGI_RGB e349;
+ public DXGI_RGB e350;
+ public DXGI_RGB e351;
+ public DXGI_RGB e352;
+ public DXGI_RGB e353;
+ public DXGI_RGB e354;
+ public DXGI_RGB e355;
+ public DXGI_RGB e356;
+ public DXGI_RGB e357;
+ public DXGI_RGB e358;
+ public DXGI_RGB e359;
+ public DXGI_RGB e360;
+ public DXGI_RGB e361;
+ public DXGI_RGB e362;
+ public DXGI_RGB e363;
+ public DXGI_RGB e364;
+ public DXGI_RGB e365;
+ public DXGI_RGB e366;
+ public DXGI_RGB e367;
+ public DXGI_RGB e368;
+ public DXGI_RGB e369;
+ public DXGI_RGB e370;
+ public DXGI_RGB e371;
+ public DXGI_RGB e372;
+ public DXGI_RGB e373;
+ public DXGI_RGB e374;
+ public DXGI_RGB e375;
+ public DXGI_RGB e376;
+ public DXGI_RGB e377;
+ public DXGI_RGB e378;
+ public DXGI_RGB e379;
+ public DXGI_RGB e380;
+ public DXGI_RGB e381;
+ public DXGI_RGB e382;
+ public DXGI_RGB e383;
+ public DXGI_RGB e384;
+ public DXGI_RGB e385;
+ public DXGI_RGB e386;
+ public DXGI_RGB e387;
+ public DXGI_RGB e388;
+ public DXGI_RGB e389;
+ public DXGI_RGB e390;
+ public DXGI_RGB e391;
+ public DXGI_RGB e392;
+ public DXGI_RGB e393;
+ public DXGI_RGB e394;
+ public DXGI_RGB e395;
+ public DXGI_RGB e396;
+ public DXGI_RGB e397;
+ public DXGI_RGB e398;
+ public DXGI_RGB e399;
+ public DXGI_RGB e400;
+ public DXGI_RGB e401;
+ public DXGI_RGB e402;
+ public DXGI_RGB e403;
+ public DXGI_RGB e404;
+ public DXGI_RGB e405;
+ public DXGI_RGB e406;
+ public DXGI_RGB e407;
+ public DXGI_RGB e408;
+ public DXGI_RGB e409;
+ public DXGI_RGB e410;
+ public DXGI_RGB e411;
+ public DXGI_RGB e412;
+ public DXGI_RGB e413;
+ public DXGI_RGB e414;
+ public DXGI_RGB e415;
+ public DXGI_RGB e416;
+ public DXGI_RGB e417;
+ public DXGI_RGB e418;
+ public DXGI_RGB e419;
+ public DXGI_RGB e420;
+ public DXGI_RGB e421;
+ public DXGI_RGB e422;
+ public DXGI_RGB e423;
+ public DXGI_RGB e424;
+ public DXGI_RGB e425;
+ public DXGI_RGB e426;
+ public DXGI_RGB e427;
+ public DXGI_RGB e428;
+ public DXGI_RGB e429;
+ public DXGI_RGB e430;
+ public DXGI_RGB e431;
+ public DXGI_RGB e432;
+ public DXGI_RGB e433;
+ public DXGI_RGB e434;
+ public DXGI_RGB e435;
+ public DXGI_RGB e436;
+ public DXGI_RGB e437;
+ public DXGI_RGB e438;
+ public DXGI_RGB e439;
+ public DXGI_RGB e440;
+ public DXGI_RGB e441;
+ public DXGI_RGB e442;
+ public DXGI_RGB e443;
+ public DXGI_RGB e444;
+ public DXGI_RGB e445;
+ public DXGI_RGB e446;
+ public DXGI_RGB e447;
+ public DXGI_RGB e448;
+ public DXGI_RGB e449;
+ public DXGI_RGB e450;
+ public DXGI_RGB e451;
+ public DXGI_RGB e452;
+ public DXGI_RGB e453;
+ public DXGI_RGB e454;
+ public DXGI_RGB e455;
+ public DXGI_RGB e456;
+ public DXGI_RGB e457;
+ public DXGI_RGB e458;
+ public DXGI_RGB e459;
+ public DXGI_RGB e460;
+ public DXGI_RGB e461;
+ public DXGI_RGB e462;
+ public DXGI_RGB e463;
+ public DXGI_RGB e464;
+ public DXGI_RGB e465;
+ public DXGI_RGB e466;
+ public DXGI_RGB e467;
+ public DXGI_RGB e468;
+ public DXGI_RGB e469;
+ public DXGI_RGB e470;
+ public DXGI_RGB e471;
+ public DXGI_RGB e472;
+ public DXGI_RGB e473;
+ public DXGI_RGB e474;
+ public DXGI_RGB e475;
+ public DXGI_RGB e476;
+ public DXGI_RGB e477;
+ public DXGI_RGB e478;
+ public DXGI_RGB e479;
+ public DXGI_RGB e480;
+ public DXGI_RGB e481;
+ public DXGI_RGB e482;
+ public DXGI_RGB e483;
+ public DXGI_RGB e484;
+ public DXGI_RGB e485;
+ public DXGI_RGB e486;
+ public DXGI_RGB e487;
+ public DXGI_RGB e488;
+ public DXGI_RGB e489;
+ public DXGI_RGB e490;
+ public DXGI_RGB e491;
+ public DXGI_RGB e492;
+ public DXGI_RGB e493;
+ public DXGI_RGB e494;
+ public DXGI_RGB e495;
+ public DXGI_RGB e496;
+ public DXGI_RGB e497;
+ public DXGI_RGB e498;
+ public DXGI_RGB e499;
+ public DXGI_RGB e500;
+ public DXGI_RGB e501;
+ public DXGI_RGB e502;
+ public DXGI_RGB e503;
+ public DXGI_RGB e504;
+ public DXGI_RGB e505;
+ public DXGI_RGB e506;
+ public DXGI_RGB e507;
+ public DXGI_RGB e508;
+ public DXGI_RGB e509;
+ public DXGI_RGB e510;
+ public DXGI_RGB e511;
+ public DXGI_RGB e512;
+ public DXGI_RGB e513;
+ public DXGI_RGB e514;
+ public DXGI_RGB e515;
+ public DXGI_RGB e516;
+ public DXGI_RGB e517;
+ public DXGI_RGB e518;
+ public DXGI_RGB e519;
+ public DXGI_RGB e520;
+ public DXGI_RGB e521;
+ public DXGI_RGB e522;
+ public DXGI_RGB e523;
+ public DXGI_RGB e524;
+ public DXGI_RGB e525;
+ public DXGI_RGB e526;
+ public DXGI_RGB e527;
+ public DXGI_RGB e528;
+ public DXGI_RGB e529;
+ public DXGI_RGB e530;
+ public DXGI_RGB e531;
+ public DXGI_RGB e532;
+ public DXGI_RGB e533;
+ public DXGI_RGB e534;
+ public DXGI_RGB e535;
+ public DXGI_RGB e536;
+ public DXGI_RGB e537;
+ public DXGI_RGB e538;
+ public DXGI_RGB e539;
+ public DXGI_RGB e540;
+ public DXGI_RGB e541;
+ public DXGI_RGB e542;
+ public DXGI_RGB e543;
+ public DXGI_RGB e544;
+ public DXGI_RGB e545;
+ public DXGI_RGB e546;
+ public DXGI_RGB e547;
+ public DXGI_RGB e548;
+ public DXGI_RGB e549;
+ public DXGI_RGB e550;
+ public DXGI_RGB e551;
+ public DXGI_RGB e552;
+ public DXGI_RGB e553;
+ public DXGI_RGB e554;
+ public DXGI_RGB e555;
+ public DXGI_RGB e556;
+ public DXGI_RGB e557;
+ public DXGI_RGB e558;
+ public DXGI_RGB e559;
+ public DXGI_RGB e560;
+ public DXGI_RGB e561;
+ public DXGI_RGB e562;
+ public DXGI_RGB e563;
+ public DXGI_RGB e564;
+ public DXGI_RGB e565;
+ public DXGI_RGB e566;
+ public DXGI_RGB e567;
+ public DXGI_RGB e568;
+ public DXGI_RGB e569;
+ public DXGI_RGB e570;
+ public DXGI_RGB e571;
+ public DXGI_RGB e572;
+ public DXGI_RGB e573;
+ public DXGI_RGB e574;
+ public DXGI_RGB e575;
+ public DXGI_RGB e576;
+ public DXGI_RGB e577;
+ public DXGI_RGB e578;
+ public DXGI_RGB e579;
+ public DXGI_RGB e580;
+ public DXGI_RGB e581;
+ public DXGI_RGB e582;
+ public DXGI_RGB e583;
+ public DXGI_RGB e584;
+ public DXGI_RGB e585;
+ public DXGI_RGB e586;
+ public DXGI_RGB e587;
+ public DXGI_RGB e588;
+ public DXGI_RGB e589;
+ public DXGI_RGB e590;
+ public DXGI_RGB e591;
+ public DXGI_RGB e592;
+ public DXGI_RGB e593;
+ public DXGI_RGB e594;
+ public DXGI_RGB e595;
+ public DXGI_RGB e596;
+ public DXGI_RGB e597;
+ public DXGI_RGB e598;
+ public DXGI_RGB e599;
+ public DXGI_RGB e600;
+ public DXGI_RGB e601;
+ public DXGI_RGB e602;
+ public DXGI_RGB e603;
+ public DXGI_RGB e604;
+ public DXGI_RGB e605;
+ public DXGI_RGB e606;
+ public DXGI_RGB e607;
+ public DXGI_RGB e608;
+ public DXGI_RGB e609;
+ public DXGI_RGB e610;
+ public DXGI_RGB e611;
+ public DXGI_RGB e612;
+ public DXGI_RGB e613;
+ public DXGI_RGB e614;
+ public DXGI_RGB e615;
+ public DXGI_RGB e616;
+ public DXGI_RGB e617;
+ public DXGI_RGB e618;
+ public DXGI_RGB e619;
+ public DXGI_RGB e620;
+ public DXGI_RGB e621;
+ public DXGI_RGB e622;
+ public DXGI_RGB e623;
+ public DXGI_RGB e624;
+ public DXGI_RGB e625;
+ public DXGI_RGB e626;
+ public DXGI_RGB e627;
+ public DXGI_RGB e628;
+ public DXGI_RGB e629;
+ public DXGI_RGB e630;
+ public DXGI_RGB e631;
+ public DXGI_RGB e632;
+ public DXGI_RGB e633;
+ public DXGI_RGB e634;
+ public DXGI_RGB e635;
+ public DXGI_RGB e636;
+ public DXGI_RGB e637;
+ public DXGI_RGB e638;
+ public DXGI_RGB e639;
+ public DXGI_RGB e640;
+ public DXGI_RGB e641;
+ public DXGI_RGB e642;
+ public DXGI_RGB e643;
+ public DXGI_RGB e644;
+ public DXGI_RGB e645;
+ public DXGI_RGB e646;
+ public DXGI_RGB e647;
+ public DXGI_RGB e648;
+ public DXGI_RGB e649;
+ public DXGI_RGB e650;
+ public DXGI_RGB e651;
+ public DXGI_RGB e652;
+ public DXGI_RGB e653;
+ public DXGI_RGB e654;
+ public DXGI_RGB e655;
+ public DXGI_RGB e656;
+ public DXGI_RGB e657;
+ public DXGI_RGB e658;
+ public DXGI_RGB e659;
+ public DXGI_RGB e660;
+ public DXGI_RGB e661;
+ public DXGI_RGB e662;
+ public DXGI_RGB e663;
+ public DXGI_RGB e664;
+ public DXGI_RGB e665;
+ public DXGI_RGB e666;
+ public DXGI_RGB e667;
+ public DXGI_RGB e668;
+ public DXGI_RGB e669;
+ public DXGI_RGB e670;
+ public DXGI_RGB e671;
+ public DXGI_RGB e672;
+ public DXGI_RGB e673;
+ public DXGI_RGB e674;
+ public DXGI_RGB e675;
+ public DXGI_RGB e676;
+ public DXGI_RGB e677;
+ public DXGI_RGB e678;
+ public DXGI_RGB e679;
+ public DXGI_RGB e680;
+ public DXGI_RGB e681;
+ public DXGI_RGB e682;
+ public DXGI_RGB e683;
+ public DXGI_RGB e684;
+ public DXGI_RGB e685;
+ public DXGI_RGB e686;
+ public DXGI_RGB e687;
+ public DXGI_RGB e688;
+ public DXGI_RGB e689;
+ public DXGI_RGB e690;
+ public DXGI_RGB e691;
+ public DXGI_RGB e692;
+ public DXGI_RGB e693;
+ public DXGI_RGB e694;
+ public DXGI_RGB e695;
+ public DXGI_RGB e696;
+ public DXGI_RGB e697;
+ public DXGI_RGB e698;
+ public DXGI_RGB e699;
+ public DXGI_RGB e700;
+ public DXGI_RGB e701;
+ public DXGI_RGB e702;
+ public DXGI_RGB e703;
+ public DXGI_RGB e704;
+ public DXGI_RGB e705;
+ public DXGI_RGB e706;
+ public DXGI_RGB e707;
+ public DXGI_RGB e708;
+ public DXGI_RGB e709;
+ public DXGI_RGB e710;
+ public DXGI_RGB e711;
+ public DXGI_RGB e712;
+ public DXGI_RGB e713;
+ public DXGI_RGB e714;
+ public DXGI_RGB e715;
+ public DXGI_RGB e716;
+ public DXGI_RGB e717;
+ public DXGI_RGB e718;
+ public DXGI_RGB e719;
+ public DXGI_RGB e720;
+ public DXGI_RGB e721;
+ public DXGI_RGB e722;
+ public DXGI_RGB e723;
+ public DXGI_RGB e724;
+ public DXGI_RGB e725;
+ public DXGI_RGB e726;
+ public DXGI_RGB e727;
+ public DXGI_RGB e728;
+ public DXGI_RGB e729;
+ public DXGI_RGB e730;
+ public DXGI_RGB e731;
+ public DXGI_RGB e732;
+ public DXGI_RGB e733;
+ public DXGI_RGB e734;
+ public DXGI_RGB e735;
+ public DXGI_RGB e736;
+ public DXGI_RGB e737;
+ public DXGI_RGB e738;
+ public DXGI_RGB e739;
+ public DXGI_RGB e740;
+ public DXGI_RGB e741;
+ public DXGI_RGB e742;
+ public DXGI_RGB e743;
+ public DXGI_RGB e744;
+ public DXGI_RGB e745;
+ public DXGI_RGB e746;
+ public DXGI_RGB e747;
+ public DXGI_RGB e748;
+ public DXGI_RGB e749;
+ public DXGI_RGB e750;
+ public DXGI_RGB e751;
+ public DXGI_RGB e752;
+ public DXGI_RGB e753;
+ public DXGI_RGB e754;
+ public DXGI_RGB e755;
+ public DXGI_RGB e756;
+ public DXGI_RGB e757;
+ public DXGI_RGB e758;
+ public DXGI_RGB e759;
+ public DXGI_RGB e760;
+ public DXGI_RGB e761;
+ public DXGI_RGB e762;
+ public DXGI_RGB e763;
+ public DXGI_RGB e764;
+ public DXGI_RGB e765;
+ public DXGI_RGB e766;
+ public DXGI_RGB e767;
+ public DXGI_RGB e768;
+ public DXGI_RGB e769;
+ public DXGI_RGB e770;
+ public DXGI_RGB e771;
+ public DXGI_RGB e772;
+ public DXGI_RGB e773;
+ public DXGI_RGB e774;
+ public DXGI_RGB e775;
+ public DXGI_RGB e776;
+ public DXGI_RGB e777;
+ public DXGI_RGB e778;
+ public DXGI_RGB e779;
+ public DXGI_RGB e780;
+ public DXGI_RGB e781;
+ public DXGI_RGB e782;
+ public DXGI_RGB e783;
+ public DXGI_RGB e784;
+ public DXGI_RGB e785;
+ public DXGI_RGB e786;
+ public DXGI_RGB e787;
+ public DXGI_RGB e788;
+ public DXGI_RGB e789;
+ public DXGI_RGB e790;
+ public DXGI_RGB e791;
+ public DXGI_RGB e792;
+ public DXGI_RGB e793;
+ public DXGI_RGB e794;
+ public DXGI_RGB e795;
+ public DXGI_RGB e796;
+ public DXGI_RGB e797;
+ public DXGI_RGB e798;
+ public DXGI_RGB e799;
+ public DXGI_RGB e800;
+ public DXGI_RGB e801;
+ public DXGI_RGB e802;
+ public DXGI_RGB e803;
+ public DXGI_RGB e804;
+ public DXGI_RGB e805;
+ public DXGI_RGB e806;
+ public DXGI_RGB e807;
+ public DXGI_RGB e808;
+ public DXGI_RGB e809;
+ public DXGI_RGB e810;
+ public DXGI_RGB e811;
+ public DXGI_RGB e812;
+ public DXGI_RGB e813;
+ public DXGI_RGB e814;
+ public DXGI_RGB e815;
+ public DXGI_RGB e816;
+ public DXGI_RGB e817;
+ public DXGI_RGB e818;
+ public DXGI_RGB e819;
+ public DXGI_RGB e820;
+ public DXGI_RGB e821;
+ public DXGI_RGB e822;
+ public DXGI_RGB e823;
+ public DXGI_RGB e824;
+ public DXGI_RGB e825;
+ public DXGI_RGB e826;
+ public DXGI_RGB e827;
+ public DXGI_RGB e828;
+ public DXGI_RGB e829;
+ public DXGI_RGB e830;
+ public DXGI_RGB e831;
+ public DXGI_RGB e832;
+ public DXGI_RGB e833;
+ public DXGI_RGB e834;
+ public DXGI_RGB e835;
+ public DXGI_RGB e836;
+ public DXGI_RGB e837;
+ public DXGI_RGB e838;
+ public DXGI_RGB e839;
+ public DXGI_RGB e840;
+ public DXGI_RGB e841;
+ public DXGI_RGB e842;
+ public DXGI_RGB e843;
+ public DXGI_RGB e844;
+ public DXGI_RGB e845;
+ public DXGI_RGB e846;
+ public DXGI_RGB e847;
+ public DXGI_RGB e848;
+ public DXGI_RGB e849;
+ public DXGI_RGB e850;
+ public DXGI_RGB e851;
+ public DXGI_RGB e852;
+ public DXGI_RGB e853;
+ public DXGI_RGB e854;
+ public DXGI_RGB e855;
+ public DXGI_RGB e856;
+ public DXGI_RGB e857;
+ public DXGI_RGB e858;
+ public DXGI_RGB e859;
+ public DXGI_RGB e860;
+ public DXGI_RGB e861;
+ public DXGI_RGB e862;
+ public DXGI_RGB e863;
+ public DXGI_RGB e864;
+ public DXGI_RGB e865;
+ public DXGI_RGB e866;
+ public DXGI_RGB e867;
+ public DXGI_RGB e868;
+ public DXGI_RGB e869;
+ public DXGI_RGB e870;
+ public DXGI_RGB e871;
+ public DXGI_RGB e872;
+ public DXGI_RGB e873;
+ public DXGI_RGB e874;
+ public DXGI_RGB e875;
+ public DXGI_RGB e876;
+ public DXGI_RGB e877;
+ public DXGI_RGB e878;
+ public DXGI_RGB e879;
+ public DXGI_RGB e880;
+ public DXGI_RGB e881;
+ public DXGI_RGB e882;
+ public DXGI_RGB e883;
+ public DXGI_RGB e884;
+ public DXGI_RGB e885;
+ public DXGI_RGB e886;
+ public DXGI_RGB e887;
+ public DXGI_RGB e888;
+ public DXGI_RGB e889;
+ public DXGI_RGB e890;
+ public DXGI_RGB e891;
+ public DXGI_RGB e892;
+ public DXGI_RGB e893;
+ public DXGI_RGB e894;
+ public DXGI_RGB e895;
+ public DXGI_RGB e896;
+ public DXGI_RGB e897;
+ public DXGI_RGB e898;
+ public DXGI_RGB e899;
+ public DXGI_RGB e900;
+ public DXGI_RGB e901;
+ public DXGI_RGB e902;
+ public DXGI_RGB e903;
+ public DXGI_RGB e904;
+ public DXGI_RGB e905;
+ public DXGI_RGB e906;
+ public DXGI_RGB e907;
+ public DXGI_RGB e908;
+ public DXGI_RGB e909;
+ public DXGI_RGB e910;
+ public DXGI_RGB e911;
+ public DXGI_RGB e912;
+ public DXGI_RGB e913;
+ public DXGI_RGB e914;
+ public DXGI_RGB e915;
+ public DXGI_RGB e916;
+ public DXGI_RGB e917;
+ public DXGI_RGB e918;
+ public DXGI_RGB e919;
+ public DXGI_RGB e920;
+ public DXGI_RGB e921;
+ public DXGI_RGB e922;
+ public DXGI_RGB e923;
+ public DXGI_RGB e924;
+ public DXGI_RGB e925;
+ public DXGI_RGB e926;
+ public DXGI_RGB e927;
+ public DXGI_RGB e928;
+ public DXGI_RGB e929;
+ public DXGI_RGB e930;
+ public DXGI_RGB e931;
+ public DXGI_RGB e932;
+ public DXGI_RGB e933;
+ public DXGI_RGB e934;
+ public DXGI_RGB e935;
+ public DXGI_RGB e936;
+ public DXGI_RGB e937;
+ public DXGI_RGB e938;
+ public DXGI_RGB e939;
+ public DXGI_RGB e940;
+ public DXGI_RGB e941;
+ public DXGI_RGB e942;
+ public DXGI_RGB e943;
+ public DXGI_RGB e944;
+ public DXGI_RGB e945;
+ public DXGI_RGB e946;
+ public DXGI_RGB e947;
+ public DXGI_RGB e948;
+ public DXGI_RGB e949;
+ public DXGI_RGB e950;
+ public DXGI_RGB e951;
+ public DXGI_RGB e952;
+ public DXGI_RGB e953;
+ public DXGI_RGB e954;
+ public DXGI_RGB e955;
+ public DXGI_RGB e956;
+ public DXGI_RGB e957;
+ public DXGI_RGB e958;
+ public DXGI_RGB e959;
+ public DXGI_RGB e960;
+ public DXGI_RGB e961;
+ public DXGI_RGB e962;
+ public DXGI_RGB e963;
+ public DXGI_RGB e964;
+ public DXGI_RGB e965;
+ public DXGI_RGB e966;
+ public DXGI_RGB e967;
+ public DXGI_RGB e968;
+ public DXGI_RGB e969;
+ public DXGI_RGB e970;
+ public DXGI_RGB e971;
+ public DXGI_RGB e972;
+ public DXGI_RGB e973;
+ public DXGI_RGB e974;
+ public DXGI_RGB e975;
+ public DXGI_RGB e976;
+ public DXGI_RGB e977;
+ public DXGI_RGB e978;
+ public DXGI_RGB e979;
+ public DXGI_RGB e980;
+ public DXGI_RGB e981;
+ public DXGI_RGB e982;
+ public DXGI_RGB e983;
+ public DXGI_RGB e984;
+ public DXGI_RGB e985;
+ public DXGI_RGB e986;
+ public DXGI_RGB e987;
+ public DXGI_RGB e988;
+ public DXGI_RGB e989;
+ public DXGI_RGB e990;
+ public DXGI_RGB e991;
+ public DXGI_RGB e992;
+ public DXGI_RGB e993;
+ public DXGI_RGB e994;
+ public DXGI_RGB e995;
+ public DXGI_RGB e996;
+ public DXGI_RGB e997;
+ public DXGI_RGB e998;
+ public DXGI_RGB e999;
+ public DXGI_RGB e1000;
+ public DXGI_RGB e1001;
+ public DXGI_RGB e1002;
+ public DXGI_RGB e1003;
+ public DXGI_RGB e1004;
+ public DXGI_RGB e1005;
+ public DXGI_RGB e1006;
+ public DXGI_RGB e1007;
+ public DXGI_RGB e1008;
+ public DXGI_RGB e1009;
+ public DXGI_RGB e1010;
+ public DXGI_RGB e1011;
+ public DXGI_RGB e1012;
+ public DXGI_RGB e1013;
+ public DXGI_RGB e1014;
+ public DXGI_RGB e1015;
+ public DXGI_RGB e1016;
+ public DXGI_RGB e1017;
+ public DXGI_RGB e1018;
+ public DXGI_RGB e1019;
+ public DXGI_RGB e1020;
+ public DXGI_RGB e1021;
+ public DXGI_RGB e1022;
+ public DXGI_RGB e1023;
+ public DXGI_RGB e1024;
+#if NET6_0_OR_GREATER
+ public ref DXGI_RGB this[int index]
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return ref AsSpan()[index];
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Span AsSpan() => MemoryMarshal.CreateSpan(ref e0, 1025);
+#else
+ // there is no way to do this outside of terrible unsafe code. Don't do this in .Net Standard 2.0
+
+ public DXGI_RGB this[int index]
+ {
+ get
+ {
+ if ((uint)index > 1025)
+ throw new ArgumentOutOfRangeException("index");
+
+ fixed (DXGI_RGB* basePtr = &e0)
+ {
+ DXGI_RGB* newPtr = basePtr + index;
+ return *newPtr;
+ }
+ }
+ set
+ {
+ if ((uint)index > 1025)
+ throw new ArgumentOutOfRangeException("index");
+
+ fixed (DXGI_RGB* basePtr = &e0)
+ {
+ DXGI_RGB* newPtr = basePtr + index;
+ *newPtr = value;
+ }
+ }
+ }
+#endif
+ }
+ }
+
+ internal unsafe struct DEVMODEW
+ {
+ public fixed ushort dmDeviceName[32];
+ public short dmSpecVersion;
+ public short dmDriverVersion;
+ public short dmSize;
+ public short dmDriverExtra;
+ public int dmFields;
+ public short dmOrientation;
+ public short dmPaperSize;
+ public short dmPaperLength;
+ public short dmPaperWidth;
+ public short dmScale;
+ public short dmCopies;
+ public short dmDefaultSource;
+ public short dmPrintQuality;
+ public short dmColor;
+ public short dmDuplex;
+ public short dmYResolution;
+ public short dmTTOption;
+ public short dmCollate;
+ public fixed ushort dmFormName[32];
+ public short dmUnusedPadding;
+ public short dmBitsPerPel;
+ public int dmPelsWidth;
+ public int dmPelsHeight;
+ public int dmDisplayFlags;
+ public int dmDisplayFrequency;
+ }
+
+ internal unsafe struct DXGI_ADAPTER_DESC
+ {
+ public fixed ushort Description[128];
+
+ public uint VendorId;
+
+ public uint DeviceId;
+
+ public uint SubSysId;
+
+ public uint Revision;
+
+ public nuint DedicatedVideoMemory;
+
+ public nuint DedicatedSystemMemory;
+
+ public nuint SharedSystemMemory;
+
+ public ulong AdapterLuid;
+ }
+
+ internal unsafe struct DXGI_ADAPTER_DESC1
+ {
+ public fixed ushort Description[128];
+
+ public uint VendorId;
+
+ public uint DeviceId;
+
+ public uint SubSysId;
+
+ public uint Revision;
+
+ public nuint DedicatedVideoMemory;
+
+ public nuint DedicatedSystemMemory;
+
+ public nuint SharedSystemMemory;
+
+ public ulong AdapterLuid;
+
+ public uint Flags;
+ }
+
+ internal unsafe struct DXGI_FRAME_STATISTICS
+ {
+ public uint PresentCount;
+
+ public uint PresentRefreshCount;
+
+ public uint SyncRefreshCount;
+
+ public ulong SyncQPCTime;
+
+ public ulong SyncGPUTime;
+ }
+
+ internal unsafe struct DXGI_GAMMA_CONTROL_CAPABILITIES
+ {
+ public int ScaleAndOffsetSupported;
+
+ public float MaxConvertedValue;
+
+ public float MinConvertedValue;
+
+ public uint NumGammaControlPoints;
+
+ public fixed float ControlPointPositions[1025];
+ }
+
+ internal unsafe struct DXGI_MAPPED_RECT
+ {
+ public int Pitch;
+
+ public byte* pBits;
+ }
+
+ internal unsafe partial struct DXGI_MODE_DESC
+ {
+ public ushort Width;
+ public ushort Height;
+ public DXGI_RATIONAL RefreshRate;
+ public DXGI_FORMAT Format;
+ public DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
+ public DXGI_MODE_SCALING Scaling;
+ }
+
+ internal unsafe partial struct DXGI_OUTPUT_DESC
+ {
+ internal fixed ushort DeviceName[32];
+
+ internal RECT DesktopCoordinates;
+
+ internal bool AttachedToDesktop;
+
+ internal DXGI_MODE_ROTATION Rotation;
+
+ internal HANDLE Monitor;
+ }
+
+ internal unsafe struct DXGI_PRESENT_PARAMETERS
+ {
+ public uint DirtyRectsCount;
+
+ public RECT* pDirtyRects;
+
+ public RECT* pScrollRect;
+
+ public POINT* pScrollOffset;
+ }
+
+ internal unsafe partial struct DXGI_RATIONAL
+ {
+ public ushort Numerator;
+ public ushort Denominator;
+ }
+
+ internal partial struct DXGI_RGB
+ {
+ public float Red;
+
+ public float Green;
+
+ public float Blue;
+ }
+
+ internal partial struct DXGI_RGBA
+ {
+ public float r;
+
+ public float g;
+
+ public float b;
+
+ public float a;
+ }
+
+ internal struct DXGI_SAMPLE_DESC
+ {
+ public uint Count;
+ public uint Quality;
+ }
+
+ internal unsafe struct DXGI_SURFACE_DESC
+ {
+ public uint Width;
+
+ public uint Height;
+
+ public DXGI_FORMAT Format;
+
+ public DXGI_SAMPLE_DESC SampleDesc;
+ }
+
+ internal unsafe partial struct DXGI_SWAP_CHAIN_DESC
+ {
+ public DXGI_MODE_DESC BufferDesc;
+ public DXGI_SAMPLE_DESC SampleDesc;
+ public uint BufferUsage;
+ public ushort BufferCount;
+ public IntPtr OutputWindow;
+ public int Windowed;
+ public DXGI_SWAP_EFFECT SwapEffect;
+ public ushort Flags;
+ }
+
+ internal struct DXGI_SWAP_CHAIN_DESC1
+ {
+ public uint Width;
+ public uint Height;
+ public DXGI_FORMAT Format;
+ public bool Stereo;
+ public DXGI_SAMPLE_DESC SampleDesc;
+ public uint BufferUsage;
+ public uint BufferCount;
+ public DXGI_SCALING Scaling;
+ public DXGI_SWAP_EFFECT SwapEffect;
+ public DXGI_ALPHA_MODE AlphaMode;
+ public uint Flags;
+ }
+
+ internal unsafe struct DXGI_SWAP_CHAIN_FULLSCREEN_DESC
+ {
+ public DXGI_RATIONAL RefreshRate;
+
+ public DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;
+
+ public DXGI_MODE_SCALING Scaling;
+
+ public int Windowed;
+ }
+
+ internal partial struct D3D11_TEXTURE2D_DESC
+ {
+ public uint Width;
+
+ public uint Height;
+
+ public uint MipLevels;
+
+ public uint ArraySize;
+
+ public DXGI_FORMAT Format;
+
+ public DXGI_SAMPLE_DESC SampleDesc;
+
+ public D3D11_USAGE Usage;
+
+ public uint BindFlags;
+
+ public uint CPUAccessFlags;
+
+ public uint MiscFlags;
+ }
+#nullable restore
+}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DirectXUnmanagedMethods.cs b/src/Windows/Avalonia.Win32/DirectX/DirectXUnmanagedMethods.cs
new file mode 100644
index 0000000000..1a739ce3d1
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DirectX/DirectXUnmanagedMethods.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Avalonia.Win32.DxgiSwapchain
+{
+ internal unsafe class DirectXUnmanagedMethods
+ {
+ // these return HRESULTs expecting Marshall to throw Win32 exceptions on failures
+ [DllImport("dxgi", ExactSpelling = true, PreserveSig = false)]
+ internal static extern void CreateDXGIFactory(ref Guid riid, out void* ppFactory);
+
+ // these return HRESULTs expecting Marshall to throw Win32 exceptions on failures
+ [DllImport("dxgi", ExactSpelling = true, PreserveSig = false)]
+ internal static extern void CreateDXGIFactory1(ref Guid riid, out void* ppFactory);
+
+ [DllImport("user32", ExactSpelling = true)]
+ internal static extern bool GetMonitorInfoW(HANDLE hMonitor, IntPtr lpmi);
+
+ [DllImport("user32", ExactSpelling = true)]
+ internal static extern bool EnumDisplaySettingsW(ushort* lpszDeviceName, uint iModeNum, DEVMODEW* lpDevMode);
+
+ [DllImport("user32", ExactSpelling = true, SetLastError = true)]
+ internal static extern bool GetClientRect(IntPtr hWnd, Interop.UnmanagedMethods.RECT* lpRect);
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
new file mode 100644
index 0000000000..8c13ecdcc1
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DirectX/DxgiConnection.cs
@@ -0,0 +1,202 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.Logging;
+using Avalonia.OpenGL.Angle;
+using Avalonia.OpenGL.Egl;
+using Avalonia.Rendering;
+using static Avalonia.Win32.Interop.UnmanagedMethods;
+using static Avalonia.Win32.DxgiSwapchain.DirectXUnmanagedMethods;
+using MicroCom.Runtime;
+
+namespace Avalonia.Win32.DxgiSwapchain
+{
+#pragma warning disable CA1416 // This should only be reachable on Windows
+#nullable enable
+ public unsafe class DxgiConnection : IRenderTimer
+ {
+ public const uint ENUM_CURRENT_SETTINGS = unchecked((uint)(-1));
+
+ public bool RunsInBackground => true;
+
+ public event Action? Tick;
+
+ private AngleWin32EglDisplay _angle;
+ private EglPlatformOpenGlInterface _gl;
+ private object _syncLock;
+
+ private IDXGIOutput? _output = null;
+
+ private Stopwatch? _stopwatch = null;
+
+ public DxgiConnection(EglPlatformOpenGlInterface gl, object syncLock)
+ {
+
+ _syncLock = syncLock;
+ _angle = (AngleWin32EglDisplay)gl.Display;
+ _gl = gl;
+ }
+
+ public EglPlatformOpenGlInterface Egl => _gl;
+
+ public static void TryCreateAndRegister(EglPlatformOpenGlInterface angle)
+ {
+ try
+ {
+ TryCreateAndRegisterCore(angle);
+ }
+ catch (Exception ex)
+ {
+ Logger.TryGet(LogEventLevel.Error, nameof(DxgiSwapchain))
+ ?.Log(null, "Unable to establish Dxgi: {0}", ex);
+ }
+ }
+
+ private unsafe void RunLoop()
+ {
+ _stopwatch = System.Diagnostics.Stopwatch.StartNew();
+ try
+ {
+ GetBestOutputToVWaitOn();
+ }
+ catch (Exception ex)
+ {
+ Logger.TryGet(LogEventLevel.Error, nameof(DxgiSwapchain))
+ ?.Log(this, $"Failed to wait for vblank, Exception: {ex.Message}, HRESULT = {ex.HResult}");
+ }
+
+ while (true)
+ {
+ try
+ {
+ lock (_syncLock)
+ {
+ if (_output is not null)
+ {
+ try
+ {
+ _output.WaitForVBlank();
+ }
+ catch (Exception ex)
+ {
+ Logger.TryGet(LogEventLevel.Error, nameof(DxgiSwapchain))
+ ?.Log(this, $"Failed to wait for vblank, Exception: {ex.Message}, HRESULT = {ex.HResult}");
+ _output.Dispose();
+ _output = null;
+ GetBestOutputToVWaitOn();
+ }
+ }
+ else
+ {
+ // well since that obviously didn't work, then let's use the lowest-common-denominator instead
+ // for reference, this has never happened on my machine,
+ // but theoretically someone could have a weirder setup out there
+ DwmFlush();
+ }
+ Tick?.Invoke(_stopwatch.Elapsed);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.TryGet(LogEventLevel.Error, nameof(DxgiSwapchain))
+ ?.Log(this, $"Failed to wait for vblank, Exception: {ex.Message}, HRESULT = {ex.HResult}");
+ }
+ }
+ }
+
+ // Note: Defining best as display with highest refresh rate on
+ private void GetBestOutputToVWaitOn()
+ {
+ double highestRefreshRate = 0.0d;
+
+ // IDXGIFactory Guid: [Guid("7B7166EC-21C7-44AE-B21A-C9AE321AE369")]
+ Guid factoryGuid = MicroComRuntime.GetGuidFor(typeof(IDXGIFactory));
+ CreateDXGIFactory(ref factoryGuid, out var factPointer);
+
+ using var fact = MicroComRuntime.CreateProxyFor(factPointer, true);
+
+ void* adapterPointer = null;
+
+ ushort adapterIndex = 0;
+
+ // this looks odd, but that's just how one enumerates adapters in DXGI
+ while (fact.EnumAdapters(adapterIndex, &adapterPointer) == 0)
+ {
+ using var adapter = MicroComRuntime.CreateProxyFor(adapterPointer, true);
+ void* outputPointer = null;
+ ushort outputIndex = 0;
+ while (adapter.EnumOutputs(outputIndex, &outputPointer) == 0)
+ {
+ using var output = MicroComRuntime.CreateProxyFor(outputPointer, true);
+ DXGI_OUTPUT_DESC outputDesc = output.Desc;
+
+
+ // this handle need not closing, by the way.
+ HANDLE monitorH = outputDesc.Monitor;
+ MONITORINFOEXW monInfo = default;
+ // by setting cbSize we tell Windows to fully populate the extended info
+
+ monInfo.Base.cbSize = sizeof(MONITORINFOEXW);
+ GetMonitorInfoW(monitorH, (IntPtr)(&monInfo));
+
+ DEVMODEW devMode = default;
+ EnumDisplaySettingsW(outputDesc.DeviceName, ENUM_CURRENT_SETTINGS, &devMode);
+
+ if (highestRefreshRate < devMode.dmDisplayFrequency)
+ {
+ // ooh I like this output!
+ if (_output is not null)
+ {
+ _output.Dispose();
+ _output = null;
+ }
+ _output = MicroComRuntime.CloneReference(output);
+ highestRefreshRate = devMode.dmDisplayFrequency;
+ }
+ // and then increment index to move onto the next monitor
+ outputIndex++;
+ }
+ // and then increment index to move onto the next display adapater
+ adapterIndex++;
+ }
+
+ }
+
+ // Used the windows composition as a blueprint for this startup/creation
+ static private bool TryCreateAndRegisterCore(EglPlatformOpenGlInterface gl)
+ {
+ var tcs = new TaskCompletionSource();
+ var pumpLock = new object();
+ var thread = new System.Threading.Thread(() =>
+ {
+ try
+ {
+ DxgiConnection connection;
+
+ connection = new DxgiConnection(gl, pumpLock);
+
+ AvaloniaLocator.CurrentMutable.BindToSelf(connection);
+ AvaloniaLocator.CurrentMutable.Bind().ToConstant(connection);
+ tcs.SetResult(true);
+ connection.RunLoop();
+ }
+ catch (Exception ex)
+ {
+ tcs.SetException(ex);
+ }
+ });
+ thread.IsBackground = true;
+ thread.SetApartmentState(System.Threading.ApartmentState.STA);
+ thread.Start();
+ // block until
+ return tcs.Task.Result;
+ }
+ }
+#nullable restore
+#pragma warning restore CA1416 // Validate platform compatibility
+}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
new file mode 100644
index 0000000000..2ab9b30d43
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DirectX/DxgiRenderTarget.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.OpenGL.Angle;
+using Avalonia.OpenGL.Egl;
+using Avalonia.OpenGL.Surfaces;
+using MicroCom.Runtime;
+using static Avalonia.OpenGL.Egl.EglGlPlatformSurfaceBase;
+using static Avalonia.Win32.Interop.UnmanagedMethods;
+
+namespace Avalonia.Win32.DxgiSwapchain
+{
+#pragma warning disable CA1416 // Validate platform compatibility, if you enter this not on windows you have messed up badly
+#nullable enable
+ public unsafe class DxgiRenderTarget : EglPlatformSurfaceRenderTargetBase
+ {
+ // DXGI_FORMAT_B8G8R8A8_UNORM is target texture format as per ANGLE documentation
+
+ public const uint DXGI_USAGE_RENDER_TARGET_OUTPUT = 0x00000020U;
+
+ private IEglWindowGlPlatformSurfaceInfo _window;
+ private EglPlatformOpenGlInterface _egl;
+ private DxgiConnection _connection;
+ private IDXGIDevice? _dxgiDevice = null;
+ private IDXGIFactory2? _dxgiFactory = null;
+ private IDXGISwapChain1? _swapChain = null;
+ private IUnknown? _renderTexture = null;
+
+ private Interop.UnmanagedMethods.RECT _clientRect = default;
+
+ private uint _flagsUsed;
+
+ private Guid ID3D11Texture2DGuid = Guid.Parse("6F15AAF2-D208-4E89-9AB4-489535D34F9C");
+
+ public DxgiRenderTarget(IEglWindowGlPlatformSurfaceInfo window, EglPlatformOpenGlInterface egl, DxgiConnection connection) : base(egl)
+ {
+ _window = window;
+ _egl = egl;
+ _connection = connection;
+
+ // the D3D device is expected to at least be an ID3D11Device
+ // but how do I wrap an IntPtr as a managed IUnknown now? Like this.
+ IUnknown pdevice = MicroComRuntime.CreateProxyFor(((AngleWin32EglDisplay)_egl.Display).GetDirect3DDevice(), false);
+
+ _dxgiDevice = pdevice.QueryInterface();
+
+ // only needing the adapter pointer to ask it for the IDXGI Factory
+ using (var adapterPointer = _dxgiDevice.Adapter)
+ {
+ Guid factoryGuid = MicroComRuntime.GetGuidFor(typeof(IDXGIFactory2));
+ _dxgiFactory = MicroComRuntime.CreateProxyFor(adapterPointer.GetParent(&factoryGuid), true);
+ }
+
+ DXGI_SWAP_CHAIN_DESC1 dxgiSwapChainDesc = new DXGI_SWAP_CHAIN_DESC1();
+
+ // standard swap chain really.
+ dxgiSwapChainDesc.Format = DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM;
+ dxgiSwapChainDesc.SampleDesc.Count = 1U;
+ dxgiSwapChainDesc.SampleDesc.Quality = 0U;
+ dxgiSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ dxgiSwapChainDesc.AlphaMode = DXGI_ALPHA_MODE.DXGI_ALPHA_MODE_IGNORE;
+ dxgiSwapChainDesc.Width = (uint)_window.Size.Width;
+ dxgiSwapChainDesc.Height = (uint)_window.Size.Height;
+ dxgiSwapChainDesc.BufferCount = 2U;
+ dxgiSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT.DXGI_SWAP_EFFECT_FLIP_DISCARD;
+
+ // okay I know this looks bad, but we're hitting our render-calls by awaiting via dxgi
+ // this is done in the DxgiConnection itself
+ _flagsUsed = dxgiSwapChainDesc.Flags = (uint)(DXGI_SWAP_CHAIN_FLAG.DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING);
+
+ _swapChain = _dxgiFactory.CreateSwapChainForHwnd
+ (
+ _dxgiDevice,
+ window.Handle,
+ &dxgiSwapChainDesc,
+ null,
+ null
+ );
+
+ Interop.UnmanagedMethods.RECT pClientRect;
+ GetClientRect(_window.Handle, out pClientRect);
+ _clientRect = pClientRect;
+ }
+
+ public override IGlPlatformSurfaceRenderingSession BeginDraw()
+ {
+ if (_swapChain is null)
+ {
+ throw new InvalidOperationException("No chain to draw on");
+ }
+
+ var contextLock = _egl.PrimaryContext.EnsureCurrent();
+ EglSurface? surface = null;
+ IDisposable? transaction = null;
+ var success = false;
+ try
+ {
+ Interop.UnmanagedMethods.RECT pClientRect;
+ GetClientRect(_window.Handle, out pClientRect);
+ if (!RectsEqual(pClientRect, _clientRect))
+ {
+ // we gotta resize
+ _clientRect = pClientRect;
+
+ if (_renderTexture is not null)
+ {
+ _renderTexture.Dispose();
+ _renderTexture = null;
+ }
+
+ _swapChain.ResizeBuffers(2,
+ (ushort)(pClientRect.right - pClientRect.left),
+ (ushort)(pClientRect.bottom - pClientRect.top),
+ DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM,
+ (ushort)_flagsUsed
+ );
+ }
+
+ var size = _window.Size;
+
+ // Get swapchain texture here
+ var texture = _renderTexture;
+ if (texture is null)
+ {
+ Guid textureGuid = ID3D11Texture2DGuid;
+ texture = MicroComRuntime.CreateProxyFor(_swapChain.GetBuffer(0, &textureGuid), true);
+ }
+ _renderTexture = texture;
+
+ // I also have to get the pointer to this texture directly
+ surface = ((AngleWin32EglDisplay)_egl.Display).WrapDirect3D11Texture(_egl, MicroComRuntime.GetNativeIntPtr(_renderTexture),
+ 0, 0, size.Width, size.Height);
+
+ var res = base.BeginDraw(surface, _window, () =>
+ {
+ _swapChain.Present((ushort)0U, (ushort)0U);
+ surface?.Dispose();
+ transaction?.Dispose();
+ contextLock?.Dispose();
+ }, true);
+ success = true;
+ return res;
+ }
+ finally
+ {
+ if (!success)
+ {
+ surface?.Dispose();
+ if (_renderTexture is not null)
+ {
+ _renderTexture.Dispose();
+ _renderTexture = null;
+ }
+ transaction?.Dispose();
+ contextLock.Dispose();
+ }
+ }
+ }
+
+ public override void Dispose()
+ {
+ base.Dispose();
+ _dxgiDevice?.Dispose();
+ _dxgiFactory?.Dispose();
+ _swapChain?.Dispose();
+ _renderTexture?.Dispose();
+ }
+
+ internal static bool RectsEqual(in RECT l, in RECT r)
+ {
+ return (l.left == r.left)
+ && (l.top == r.top)
+ && (l.right == r.right)
+ && (l.bottom == r.bottom);
+ }
+
+ }
+#pragma warning restore CA1416 // Validate platform compatibility
+#nullable restore
+}
diff --git a/src/Windows/Avalonia.Win32/DirectX/DxgiSwapchainWindow.cs b/src/Windows/Avalonia.Win32/DirectX/DxgiSwapchainWindow.cs
new file mode 100644
index 0000000000..a40d8abf80
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DirectX/DxgiSwapchainWindow.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Avalonia.OpenGL.Egl;
+using Avalonia.OpenGL.Surfaces;
+
+namespace Avalonia.Win32.DxgiSwapchain
+{
+ public class DxgiSwapchainWindow : EglGlPlatformSurfaceBase
+ {
+ private DxgiConnection _connection;
+ private EglPlatformOpenGlInterface _egl;
+ private IEglWindowGlPlatformSurfaceInfo _window;
+
+ public DxgiSwapchainWindow(DxgiConnection connection, IEglWindowGlPlatformSurfaceInfo window)
+ {
+ _connection = connection;
+ _window = window;
+ _egl = connection.Egl;
+ }
+
+ public override IGlPlatformSurfaceRenderTarget CreateGlRenderTarget()
+ {
+ using (_egl.PrimaryContext.EnsureCurrent())
+ {
+ return new DxgiRenderTarget(_window, _egl, _connection);
+ }
+ }
+ }
+}
diff --git a/src/Windows/Avalonia.Win32/DirectX/directx.idl b/src/Windows/Avalonia.Win32/DirectX/directx.idl
new file mode 100644
index 0000000000..09d1adf574
--- /dev/null
+++ b/src/Windows/Avalonia.Win32/DirectX/directx.idl
@@ -0,0 +1,305 @@
+@clr-namespace Avalonia.Win32.DxgiSwapchain
+@clr-access internal
+@clr-map FLOAT float
+@clr-map HSTRING IntPtr
+@clr-map Vector2 System.Numerics.Vector2
+@clr-map Vector3 System.Numerics.Vector3
+@clr-map Quaternion System.Numerics.Quaternion
+@clr-map Matrix4x4 System.Numerics.Matrix4x4
+@clr-map RECT Avalonia.Win32.Interop.UnmanagedMethods.RECT
+@clr-map SIZE Avalonia.Win32.Interop.UnmanagedMethods.SIZE
+@clr-map POINT Avalonia.Win32.Interop.UnmanagedMethods.POINT
+@clr-map HWND IntPtr
+@clr-map BOOL int
+@clr-map DWORD int
+@clr-map boolean int
+@clr-map BYTE byte
+@clr-map INT16 short
+@clr-map INT32 int
+@clr-map INT64 long
+@clr-map UINT ushort
+@clr-map UINT16 ushort
+@clr-map ULONG uint
+@clr-map UINT32 uint
+@clr-map UINT64 ulong
+@clr-map DOUBLE double
+@clr-map GUID System.Guid
+@clr-map REFGUID System.Guid*
+@clr-map REFIID System.Guid*
+@clr-map WCHAR System.Char
+@clr-map HMODULE void*
+@clr-map DXGI_USAGE uint
+@clr-map LARGE_INTEGER ulong
+@clr-map INT int
+@clr-map DXGI_SHARED_RESOURCE void*
+@clr-map LUID ulong
+@clr-map LPSTR ushort*
+
+
+enum DXGI_FORMAT
+{
+ DXGI_FORMAT_UNKNOWN = 0,
+ DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,
+ DXGI_FORMAT_R32G32B32A32_FLOAT = 2,
+ DXGI_FORMAT_R32G32B32A32_UINT = 3,
+ DXGI_FORMAT_R32G32B32A32_SINT = 4,
+ DXGI_FORMAT_R32G32B32_TYPELESS = 5,
+ DXGI_FORMAT_R32G32B32_FLOAT = 6,
+ DXGI_FORMAT_R32G32B32_UINT = 7,
+ DXGI_FORMAT_R32G32B32_SINT = 8,
+ DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,
+ DXGI_FORMAT_R16G16B16A16_FLOAT = 10,
+ DXGI_FORMAT_R16G16B16A16_UNORM = 11,
+ DXGI_FORMAT_R16G16B16A16_UINT = 12,
+ DXGI_FORMAT_R16G16B16A16_SNORM = 13,
+ DXGI_FORMAT_R16G16B16A16_SINT = 14,
+ DXGI_FORMAT_R32G32_TYPELESS = 15,
+ DXGI_FORMAT_R32G32_FLOAT = 16,
+ DXGI_FORMAT_R32G32_UINT = 17,
+ DXGI_FORMAT_R32G32_SINT = 18,
+ DXGI_FORMAT_R32G8X24_TYPELESS = 19,
+ DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,
+ DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,
+ DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,
+ DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,
+ DXGI_FORMAT_R10G10B10A2_UNORM = 24,
+ DXGI_FORMAT_R10G10B10A2_UINT = 25,
+ DXGI_FORMAT_R11G11B10_FLOAT = 26,
+ DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,
+ DXGI_FORMAT_R8G8B8A8_UNORM = 28,
+ DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,
+ DXGI_FORMAT_R8G8B8A8_UINT = 30,
+ DXGI_FORMAT_R8G8B8A8_SNORM = 31,
+ DXGI_FORMAT_R8G8B8A8_SINT = 32,
+ DXGI_FORMAT_R16G16_TYPELESS = 33,
+ DXGI_FORMAT_R16G16_FLOAT = 34,
+ DXGI_FORMAT_R16G16_UNORM = 35,
+ DXGI_FORMAT_R16G16_UINT = 36,
+ DXGI_FORMAT_R16G16_SNORM = 37,
+ DXGI_FORMAT_R16G16_SINT = 38,
+ DXGI_FORMAT_R32_TYPELESS = 39,
+ DXGI_FORMAT_D32_FLOAT = 40,
+ DXGI_FORMAT_R32_FLOAT = 41,
+ DXGI_FORMAT_R32_UINT = 42,
+ DXGI_FORMAT_R32_SINT = 43,
+ DXGI_FORMAT_R24G8_TYPELESS = 44,
+ DXGI_FORMAT_D24_UNORM_S8_UINT = 45,
+ DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,
+ DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,
+ DXGI_FORMAT_R8G8_TYPELESS = 48,
+ DXGI_FORMAT_R8G8_UNORM = 49,
+ DXGI_FORMAT_R8G8_UINT = 50,
+ DXGI_FORMAT_R8G8_SNORM = 51,
+ DXGI_FORMAT_R8G8_SINT = 52,
+ DXGI_FORMAT_R16_TYPELESS = 53,
+ DXGI_FORMAT_R16_FLOAT = 54,
+ DXGI_FORMAT_D16_UNORM = 55,
+ DXGI_FORMAT_R16_UNORM = 56,
+ DXGI_FORMAT_R16_UINT = 57,
+ DXGI_FORMAT_R16_SNORM = 58,
+ DXGI_FORMAT_R16_SINT = 59,
+ DXGI_FORMAT_R8_TYPELESS = 60,
+ DXGI_FORMAT_R8_UNORM = 61,
+ DXGI_FORMAT_R8_UINT = 62,
+ DXGI_FORMAT_R8_SNORM = 63,
+ DXGI_FORMAT_R8_SINT = 64,
+ DXGI_FORMAT_A8_UNORM = 65,
+ DXGI_FORMAT_R1_UNORM = 66,
+ DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,
+ DXGI_FORMAT_R8G8_B8G8_UNORM = 68,
+ DXGI_FORMAT_G8R8_G8B8_UNORM = 69,
+ DXGI_FORMAT_BC1_TYPELESS = 70,
+ DXGI_FORMAT_BC1_UNORM = 71,
+ DXGI_FORMAT_BC1_UNORM_SRGB = 72,
+ DXGI_FORMAT_BC2_TYPELESS = 73,
+ DXGI_FORMAT_BC2_UNORM = 74,
+ DXGI_FORMAT_BC2_UNORM_SRGB = 75,
+ DXGI_FORMAT_BC3_TYPELESS = 76,
+ DXGI_FORMAT_BC3_UNORM = 77,
+ DXGI_FORMAT_BC3_UNORM_SRGB = 78,
+ DXGI_FORMAT_BC4_TYPELESS = 79,
+ DXGI_FORMAT_BC4_UNORM = 80,
+ DXGI_FORMAT_BC4_SNORM = 81,
+ DXGI_FORMAT_BC5_TYPELESS = 82,
+ DXGI_FORMAT_BC5_UNORM = 83,
+ DXGI_FORMAT_BC5_SNORM = 84,
+ DXGI_FORMAT_B5G6R5_UNORM = 85,
+ DXGI_FORMAT_B5G5R5A1_UNORM = 86,
+ DXGI_FORMAT_B8G8R8A8_UNORM = 87,
+ DXGI_FORMAT_B8G8R8X8_UNORM = 88,
+ DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,
+ DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,
+ DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,
+ DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,
+ DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,
+ DXGI_FORMAT_BC6H_TYPELESS = 94,
+ DXGI_FORMAT_BC6H_UF16 = 95,
+ DXGI_FORMAT_BC6H_SF16 = 96,
+ DXGI_FORMAT_BC7_TYPELESS = 97,
+ DXGI_FORMAT_BC7_UNORM = 98,
+ DXGI_FORMAT_BC7_UNORM_SRGB = 99,
+ DXGI_FORMAT_AYUV = 100,
+ DXGI_FORMAT_Y410 = 101,
+ DXGI_FORMAT_Y416 = 102,
+ DXGI_FORMAT_NV12 = 103,
+ DXGI_FORMAT_P010 = 104,
+ DXGI_FORMAT_P016 = 105,
+ DXGI_FORMAT_420_OPAQUE = 106,
+ DXGI_FORMAT_YUY2 = 107,
+ DXGI_FORMAT_Y210 = 108,
+ DXGI_FORMAT_Y216 = 109,
+ DXGI_FORMAT_NV11 = 110,
+ DXGI_FORMAT_AI44 = 111,
+ DXGI_FORMAT_IA44 = 112,
+ DXGI_FORMAT_P8 = 113,
+ DXGI_FORMAT_A8P8 = 114,
+ DXGI_FORMAT_B4G4R4A4_UNORM = 115,
+ DXGI_FORMAT_P208 = 130,
+ DXGI_FORMAT_V208 = 131,
+ DXGI_FORMAT_V408 = 132,
+ DXGI_FORMAT_FORCE_UINT = -1
+}
+
+enum DXGI_MODE_SCANLINE_ORDER
+{
+ DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED = 0,
+ DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE = 1,
+ DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST = 2,
+ DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST = 3
+}
+
+enum DXGI_MODE_SCALING
+{
+ DXGI_MODE_SCALING_UNSPECIFIED = 0,
+ DXGI_MODE_SCALING_CENTERED = 1,
+ DXGI_MODE_SCALING_STRETCHED = 2
+}
+
+[uuid(aec22fb8-76f3-4639-9be0-28eb43a67a2e)]
+interface IDXGIObject : IUnknown
+{
+ HRESULT SetPrivateData([in] REFGUID Name, [in] UINT DataSize, [in] void** pData);
+ HRESULT SetPrivateDataInterface([in] REFGUID Name, [in] IUnknown* pUnknown);
+ HRESULT GetPrivateData([in] REFGUID Name, [in, out] UINT* pDataSize, [out] void** pData);
+ HRESULT GetParent([in] REFIID riid, [out, retval] void** ppParent);
+}
+
+[uuid(7b7166ec-21c7-44ae-b21a-c9ae321ae369)]
+interface IDXGIFactory : IDXGIObject
+{
+ INT32 EnumAdapters([in] UINT Adapter, [out] void* ppAdapter);
+ HRESULT MakeWindowAssociation(HWND WindowHandle, UINT Flags);
+ HRESULT GetWindowAssociation([out, annotation("_Out_")] HWND* pWindowHandle);
+ HRESULT CreateSwapChain([in, annotation("_In_")] IUnknown* pDevice, [in, annotation("_In_")] DXGI_SWAP_CHAIN_DESC* pDesc, [out, annotation("_COM_Outptr_")] IDXGISwapChain** ppSwapChain);
+ HRESULT CreateSoftwareAdapter([in] HMODULE Module, [out, annotation("_COM_Outptr_")] IDXGIAdapter** ppAdapter);
+}
+
+[uuid(3d3e0379-f9de-4d58-bb6c-18d62992f1a6)]
+interface IDXGIDeviceSubObject : IDXGIObject
+{
+ HRESULT GetDevice([in, annotation("_In_")] REFIID riid, [out, retval, annotation("_COM_Outptr_")] void** ppDevice);
+}
+
+[uuid(2411e7e1-12ac-4ccf-bd14-9798e8534dc0)]
+interface IDXGIAdapter : IDXGIObject
+{
+ INT32 EnumOutputs([in] UINT Output, [in, out] void* ppOutput);
+ HRESULT GetDesc([out, annotation("_Out_")] DXGI_ADAPTER_DESC* pDesc);
+ HRESULT CheckInterfaceSupport([in, annotation("_In_")] REFGUID InterfaceName,[out, annotation("_Out_")] LARGE_INTEGER* pUMDVersion);
+};
+
+[uuid(310d36a0-d2e7-4c0a-aa04-6a9d23b8886a)]
+interface IDXGISwapChain : IDXGIDeviceSubObject
+{
+ HRESULT Present([in] UINT SyncInterval, [in] UINT Flags);
+ HRESULT GetBuffer([in] UINT Buffer, [in, annotation("_In_")] REFIID riid, [in, out, annotation("_COM_Outptr_")] void** ppSurface);
+ HRESULT SetFullscreenState([in] BOOL Fullscreen, [in, annotation("_In_opt_")] IDXGIOutput* pTarget);
+ HRESULT GetFullscreenState([out, annotation("_Out_opt_")] BOOL* pFullscreen, [out, annotation("_COM_Outptr_opt_result_maybenull_")] IDXGIOutput** ppTarget);
+ HRESULT GetDesc([out] DXGI_SWAP_CHAIN_DESC* pDesc);
+ HRESULT ResizeBuffers([in] UINT BufferCount, [in] UINT Width, [in] UINT Height, [in] DXGI_FORMAT NewFormat, [in] UINT SwapChainFlags);
+ HRESULT ResizeTarget([in, annotation("_In_")] DXGI_MODE_DESC* pNewTargetParameters);
+ HRESULT GetContainingOutput([out, annotation("_COM_Outptr_")] IDXGIOutput** ppOutput);
+ HRESULT GetFrameStatistics([out, annotation("_Out_")] DXGI_FRAME_STATISTICS* pStats);
+ HRESULT GetLastPresentCount([out, annotation("_Out_")] UINT* pLastPresentCount);
+}
+
+[uuid(54ec77fa-1377-44e6-8c32-88fd5f44c84c)]
+interface IDXGIDevice : IDXGIObject
+{
+ HRESULT GetAdapter([out] IDXGIAdapter** pAdapter);
+ HRESULT CreateSurface([in, annotation("_In_")] DXGI_SURFACE_DESC* pDesc, [in] UINT NumSurfaces, [in] DXGI_USAGE Usage, [in, annotation("_In_opt_")] DXGI_SHARED_RESOURCE* pSharedResource, [out] IDXGISurface** ppSurface);
+ HRESULT QueryResourceResidency([in] IUnknown* ppResources, [out] DXGI_RESIDENCY* pResidencyStatus, [in] UINT NumResources);
+ HRESULT SetGPUThreadPriority([in] INT Priority);
+ HRESULT GetGPUThreadPriority([out, retval] INT* pPriority);
+}
+
+[uuid(ae02eedb-c735-4690-8d52-5a8dc20213aa)]
+interface IDXGIOutput : IDXGIObject
+{
+ HRESULT GetDesc([out] DXGI_OUTPUT_DESC* pDesc);
+ HRESULT GetDisplayModeList([in] DXGI_FORMAT EnumFormat, [in] UINT Flags, [in, out] UINT* pNumModes, [out] DXGI_MODE_DESC* pDesc);
+ HRESULT FindClosestMatchingMode([in, annotation("_In_")] DXGI_MODE_DESC* pModeToMatch, [out] DXGI_MODE_DESC* pClosestMatch, [in] IUnknown* pConcernedDevice);
+ HRESULT WaitForVBlank();
+ HRESULT TakeOwnership([in, annotation("_In_")] IUnknown* pDevice, BOOL Exclusive);
+ void ReleaseOwnership();
+ HRESULT GetGammaControlCapabilities([out, annotation("_Out_")] DXGI_GAMMA_CONTROL_CAPABILITIES* pGammaCaps);
+ HRESULT SetGammaControl([in, annotation("_In_")] DXGI_GAMMA_CONTROL* pArray);
+ HRESULT GetGammaControl([out, annotation("_Out_")] DXGI_GAMMA_CONTROL* pArray);
+ HRESULT SetDisplaySurface([in, annotation("_In_")] IDXGISurface* pScanoutSurface);
+ HRESULT GetDisplaySurfaceData([in, annotation("_In_")] IDXGISurface* pDestination);
+ HRESULT GetFrameStatistics([out, annotation("_Out_")] DXGI_FRAME_STATISTICS* pStats);
+}
+
+[uuid(cafcb56c-6ac3-4889-bf47-9e23bbd260ec)]
+interface IDXGISurface : IDXGIDeviceSubObject
+{
+ HRESULT GetDesc([out, annotation("_Out_")] DXGI_SURFACE_DESC* pDesc);
+ HRESULT Map([out, annotation("_Out_")] DXGI_MAPPED_RECT* pLockedRect, [in] UINT MapFlags);
+ HRESULT Unmap();
+}
+
+[uuid(770aae78-f26f-4dba-a829-253c83d1b387)]
+interface IDXGIFactory1 : IDXGIFactory
+{
+ HRESULT EnumAdapters1([in] UINT Adapter, [out, annotation("_COM_Outptr_")] IDXGIAdapter1** ppAdapter);
+ BOOL IsCurrent();
+}
+
+[uuid(29038f61-3839-4626-91fd-086879011a05)]
+interface IDXGIAdapter1 : IDXGIAdapter
+{
+ HRESULT GetDesc1([out, annotation("_Out_")] DXGI_ADAPTER_DESC1* pDesc);
+}
+
+[uuid(50c83a1c-e072-4c48-87b0-3630fa36a6d0)]
+interface IDXGIFactory2 : IDXGIFactory1
+{
+ BOOL IsWindowedStereoEnabled();
+ HRESULT CreateSwapChainForHwnd([in, annotation("_In_")] IUnknown* pDevice, [in, annotation("_In_")] HWND hWnd, [in, annotation("_In_")] DXGI_SWAP_CHAIN_DESC1* pDesc, [in, annotation("_In_opt_")] DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc, [in, annotation("_In_opt_")] IDXGIOutput* pRestrictToOutput, [out, annotation("_COM_Outptr_")] IDXGISwapChain1** ppSwapChain);
+ HRESULT CreateSwapChainForCoreWindow([in, annotation("_In_")] IUnknown* pDevice, [in, annotation("_In_")] IUnknown* pWindow, [in, annotation("_In_")] DXGI_SWAP_CHAIN_DESC1* pDesc, [in, annotation("_In_opt_")] IDXGIOutput* pRestrictToOutput, [out, annotation("_COM_Outptr_")] IDXGISwapChain1** ppSwapChain);
+ HRESULT GetSharedResourceAdapterLuid([annotation("_In_")] HANDLE hResource, [annotation("_Out_")] LUID* pLuid);
+ HRESULT RegisterStereoStatusWindow([in, annotation("_In_")] HWND WindowHandle, [in, annotation("_In_")] UINT wMsg, [out, annotation("_Out_")] DWORD* pdwCookie);
+ HRESULT RegisterStereoStatusEvent([in, annotation("_In_")] HANDLE hEvent, [out, annotation("_Out_")] DWORD* pdwCookie);
+ void UnregisterStereoStatus([in, annotation("_In_")] DWORD dwCookie);
+ HRESULT RegisterOcclusionStatusWindow([in, annotation("_In_")] HWND WindowHandle, [in, annotation("_In_")] UINT wMsg, [out, annotation("_Out_")] DWORD* pdwCookie);
+ HRESULT RegisterOcclusionStatusEvent([in, annotation("_In_")] HANDLE hEvent, [out, annotation("_Out_")] DWORD* pdwCookie);
+ void UnregisterOcclusionStatus([in, annotation("_In_")] DWORD dwCookie);
+ HRESULT CreateSwapChainForComposition([in, annotation("_In_")] IUnknown* pDevice, [in, annotation("_In_")] DXGI_SWAP_CHAIN_DESC1* pDesc, [in, annotation("_In_opt_")] IDXGIOutput* pRestrictToOutput, [out, annotation("_COM_Outptr_")] IDXGISwapChain1** ppSwapChain);
+}
+
+[uuid(790a45f7-0d42-4876-983a-0a55cfe6f4aa)]
+interface IDXGISwapChain1 : IDXGISwapChain
+{
+ HRESULT GetDesc1([out, annotation("_Out_")] DXGI_SWAP_CHAIN_DESC1* pDesc);
+ HRESULT GetFullscreenDesc([out, annotation("_Out_")] DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pDesc);
+ HRESULT GetHwnd([out, annotation("_Out_")] HWND* pHwnd);
+ HRESULT GetCoreWindow([in, annotation("_In_")] REFIID refiid, [out, annotation("_COM_Outptr_")] void** ppUnk);
+ HRESULT Present1([in] UINT SyncInterval, [in] UINT PresentFlags, [in, annotation("_In_")] DXGI_PRESENT_PARAMETERS* pPresentParameters);
+ BOOL IsTemporaryMonoSupported();
+ HRESULT GetRestrictToOutput([out, annotation("_Out_")] IDXGIOutput** ppRestrictToOutput);
+ HRESULT SetBackgroundColor([in, annotation("_In_")] DXGI_RGBA* pColor);
+ HRESULT GetBackgroundColor([out, annotation("_Out_")] DXGI_RGBA* pColor);
+ HRESULT SetRotation([in, annotation("_In_")] DXGI_MODE_ROTATION Rotation);
+ HRESULT GetRotation([out, annotation("_Out_")] DXGI_MODE_ROTATION* pRotation);
+}
+
diff --git a/src/Windows/Avalonia.Win32/Win32GlManager.cs b/src/Windows/Avalonia.Win32/Win32GlManager.cs
index 39a742d1ac..204acc82c9 100644
--- a/src/Windows/Avalonia.Win32/Win32GlManager.cs
+++ b/src/Windows/Avalonia.Win32/Win32GlManager.cs
@@ -2,6 +2,7 @@ using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
+using Avalonia.Win32.DxgiSwapchain;
using Avalonia.Win32.OpenGl;
using Avalonia.Win32.WinRT.Composition;
@@ -49,6 +50,10 @@ namespace Avalonia.Win32
{
WinUICompositorConnection.TryCreateAndRegister(egl, opts.CompositionBackdropCornerRadius);
}
+ else if (opts.UseLowLatencyDxgiSwapChain)
+ {
+ DxgiConnection.TryCreateAndRegister(egl);
+ }
}
return egl;
diff --git a/src/Windows/Avalonia.Win32/Win32Platform.cs b/src/Windows/Avalonia.Win32/Win32Platform.cs
index 18977ec4c3..27a3ce483b 100644
--- a/src/Windows/Avalonia.Win32/Win32Platform.cs
+++ b/src/Windows/Avalonia.Win32/Win32Platform.cs
@@ -96,6 +96,16 @@ namespace Avalonia
/// This can be useful when you need a rounded-corner blurred Windows 10 app, or borderless Windows 11 app
///
public float? CompositionBackdropCornerRadius { get; set; }
+
+ ///
+ /// When is active, renders Avalonia through a low-latency Dxgi Swapchain.
+ /// Requires Feature Level 11_3 to be active, Windows 8.1+ Any Subversion.
+ /// This is only recommended if low input latency is desirable, and there is no need for the transparency
+ /// and stylings / blurrings offered by
+ /// This is mutually exclusive with
+ /// which if active will override this setting.
+ ///
+ public bool UseLowLatencyDxgiSwapChain { get; set; } = false;
}
}
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 800524f83c..55e030fdf4 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -26,6 +26,7 @@ using static Avalonia.Win32.Interop.UnmanagedMethods;
using Avalonia.Collections.Pooled;
using Avalonia.Metadata;
using Avalonia.Platform.Storage;
+using Avalonia.Win32.DxgiSwapchain;
namespace Avalonia.Win32
{
@@ -63,6 +64,7 @@ namespace Avalonia.Win32
private Thickness _offScreenMargin;
private double _extendTitleBarHint = -1;
private bool _isUsingComposition;
+ private bool _isUsingDxgiSwapchain;
private IBlurHost _blurHost;
private PlatformResizeReason _resizeReason;
private MOUSEMOVEPOINT _lastWmMousePoint;
@@ -143,6 +145,16 @@ namespace Avalonia.Win32
egl.Display is AngleWin32EglDisplay angleDisplay &&
angleDisplay.PlatformApi == AngleOptions.PlatformApi.DirectX11;
+ DxgiConnection dxgiConnection = null;
+ if (!_isUsingComposition)
+ {
+ dxgiConnection = AvaloniaLocator.Current.GetService();
+ _isUsingDxgiSwapchain = dxgiConnection is { } &&
+ glPlatform is EglPlatformOpenGlInterface eglDxgi &&
+ eglDxgi.Display is AngleWin32EglDisplay angleDisplayDxgi &&
+ angleDisplayDxgi.PlatformApi == AngleOptions.PlatformApi.DirectX11;
+ }
+
_wmPointerEnabled = Win32Platform.WindowsVersion >= PlatformConstants.Windows8;
CreateWindow();
@@ -159,6 +171,11 @@ namespace Avalonia.Win32
_isUsingComposition = true;
}
+ else if (_isUsingDxgiSwapchain)
+ {
+ var dxgigl = new DxgiSwapchainWindow(dxgiConnection, this);
+ _gl = dxgigl;
+ }
else
{
if (glPlatform is EglPlatformOpenGlInterface egl2)