Browse Source

Add Support for low-latency Dxgi-swapchain based presentation model (#9572)

* Got the swapchain working

* Removed unneeded field

* Code cleanup

* Fixed and added custom control with smiles.

* Update DXGI_SWAP_CHAIN_FLAG.cs

All of the new members should be internal. Leaving the minimum (handles?) for the interoperability.

* > Please, use our COM interop codegen instead. It provides at least some safety with reference tracking / disposal

DONE

* Code cleanup, using statements for correct disposal, disposing of fields in the render-target.

* Further code refactoring, reorganized folder structure under DirectX

Co-authored-by: [email protected] <[email protected]>
ShadowMarker789 2 years ago
parent
commit
2f3c5ef98f

+ 9 - 0
samples/ControlCatalog.NetCore/Program.cs

@@ -99,6 +99,15 @@ namespace ControlCatalog.NetCore
                 SilenceConsole();
                 SilenceConsole();
                 return builder.StartLinuxDrm(args, scaling: GetScaling());
                 return builder.StartLinuxDrm(args, scaling: GetScaling());
             }
             }
+            else if (args.Contains("--dxgi"))
+            {
+                builder.With(new Win32PlatformOptions()
+                {
+                    UseLowLatencyDxgiSwapChain = true,
+                    UseWindowsUIComposition = false
+                });
+                return builder.StartWithClassicDesktopLifetime(args);
+            }
             else
             else
                 return builder.StartWithClassicDesktopLifetime(args);
                 return builder.StartWithClassicDesktopLifetime(args);
         }
         }

+ 11 - 0
samples/ControlCatalog.NetCore/Properties/launchSettings.json

@@ -0,0 +1,11 @@
+{
+  "profiles": {
+    "ControlCatalog.NetCore": {
+      "commandName": "Project"
+    },
+    "Dxgi": {
+      "commandName": "Project",
+      "commandLineArgs": "--dxgi"
+    }
+  }
+}

+ 10 - 0
samples/ControlCatalog/ControlCatalog.csproj

@@ -33,4 +33,14 @@
   </ItemGroup>
   </ItemGroup>
 
 
   <Import Project="..\..\build\BuildTargets.targets" />
   <Import Project="..\..\build\BuildTargets.targets" />
+
+  <ItemGroup>
+    <None Remove="Pages\CustomDrawing.xaml" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <AvaloniaResource Update="Pages\CustomDrawing.xaml">
+      <Generator></Generator>
+    </AvaloniaResource>
+  </ItemGroup>
 </Project>
 </Project>

+ 29 - 0
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;
+        }
+    }
+}

+ 3 - 0
samples/ControlCatalog/MainView.xaml

@@ -66,6 +66,9 @@
       <TabItem Header="Cursor" ScrollViewer.VerticalScrollBarVisibility="Disabled">
       <TabItem Header="Cursor" ScrollViewer.VerticalScrollBarVisibility="Disabled">
         <pages:CursorPage />
         <pages:CursorPage />
       </TabItem>
       </TabItem>
+      <TabItem Header="Custom Drawing" ScrollViewer.VerticalScrollBarVisibility="Disabled">
+        <pages:CustomDrawing/>
+      </TabItem>
       <TabItem Header="DataGrid"
       <TabItem Header="DataGrid"
                ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                ScrollViewer.HorizontalScrollBarVisibility="Disabled"
                ScrollViewer.VerticalScrollBarVisibility="Disabled">
                ScrollViewer.VerticalScrollBarVisibility="Disabled">

+ 107 - 0
samples/ControlCatalog/Pages/CustomDrawing.xaml

@@ -0,0 +1,107 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:local="using:ControlCatalog.Pages"
+             xmlns:converters="using:ControlCatalog.Converter"
+             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+             x:Class="ControlCatalog.Pages.CustomDrawing">
+
+  <UserControl.Resources>
+    <converters:DegToRadConverter x:Key="DegToRadConverter"/>
+  </UserControl.Resources>
+  
+  <Grid>
+    <Grid.ColumnDefinitions>
+      <ColumnDefinition/>
+      <ColumnDefinition/>
+      <ColumnDefinition/>
+    </Grid.ColumnDefinitions>
+    <Grid.RowDefinitions>
+      <RowDefinition Height="Auto"/>
+      <RowDefinition/>
+    </Grid.RowDefinitions>
+
+    <StackPanel Orientation="Vertical">
+      <TextBlock Text="Translation" HorizontalAlignment="Center"/>
+      <Grid ColumnDefinitions="*,*"
+            RowDefinitions="Auto,Auto"
+            >
+        <TextBlock Text="Horizontal"/>
+        <TextBlock Text="Vertical" Grid.Column="1"/>
+        <TextBox IsEnabled="False" 
+                 Text="{Binding ElementName=CustomDrawingControl,
+                  Path=ViewportCenterX,
+                  Mode=OneWay,
+                  StringFormat=\{0:g4\}}"
+                 Grid.Row="1"
+                 />
+        <TextBox IsEnabled="False"
+                 Text="{Binding ElementName=CustomDrawingControl,
+                  Path=ViewportCenterY, 
+                  Mode=OneWay,
+                  StringFormat=\{0:g4\}}"
+                 Grid.Row="1" Grid.Column="1"
+                 />
+      </Grid>
+    </StackPanel>
+
+    <StackPanel Orientation="Vertical" Grid.Column="1"
+                >
+      <TextBlock Text="Rotation" HorizontalAlignment="Center"/>
+      <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
+                  >
+        <Button Content="➖" Width="40" Height="40"
+                VerticalContentAlignment="Center"
+                VerticalAlignment="Center"
+                Click="RotateMinus"
+                />
+        <TextBox IsEnabled="False"
+                 Text="{Binding ElementName=CustomDrawingControl,
+                  Path=Rotation, 
+                  Converter={StaticResource DegToRadConverter},
+                  Mode=OneWay,
+                  StringFormat=\{0:g4\}}"
+                 Grid.Row="1" Grid.Column="1"
+                 />
+        <Button Content="➕" Width="40" Height="40"
+                VerticalContentAlignment="Center"
+                VerticalAlignment="Center"
+                Click="RotatePlus"
+                />
+      </StackPanel>
+    </StackPanel>
+
+    <StackPanel Orientation="Vertical" Grid.Column="2"
+                >
+      <TextBlock Text="Scale" HorizontalAlignment="Center"/>
+      <StackPanel Orientation="Horizontal" HorizontalAlignment="Center"
+                  >
+        <Button Content="➖" Width="40" Height="40"
+                VerticalContentAlignment="Center"
+                VerticalAlignment="Center"
+                Click="ZoomOut"
+                />
+        <TextBox IsEnabled="False"
+                 Text="{Binding ElementName=CustomDrawingControl,
+                  Path=Scale, 
+                  Mode=OneWay,
+                  StringFormat=\{0:g4\}}"
+                 Grid.Row="1" Grid.Column="1"
+                 />
+        <Button Content="➕" Width="40" Height="40"
+                VerticalContentAlignment="Center"
+                VerticalAlignment="Center"
+                Click="ZoomIn"
+                />
+      </StackPanel>
+    </StackPanel>
+    
+    <Grid Grid.Row="1" Grid.ColumnSpan="3" ClipToBounds="True">
+      <local:CustomDrawingExampleControl
+        x:Name="CustomDrawingControl"
+        />
+    </Grid>
+  </Grid>
+  
+</UserControl>

+ 67 - 0
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<CustomDrawingExampleControl>("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;
+        }
+    }
+}

+ 215 - 0
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<double> ScaleProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Scale), 1.0d);
+        public double Scale { get => GetValue(ScaleProperty); set => SetValue(ScaleProperty, value); }
+
+        public StyledProperty<double> RotationProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(Rotation));
+        /// <summary>
+        /// Rotation, measured in Radians!
+        /// </summary>
+        public double Rotation
+        {
+            get => GetValue(RotationProperty);
+            set
+            {
+                double valueToUse = value % (Math.PI * 2);
+                SetValue(RotationProperty, valueToUse);
+            }
+        }
+
+        public StyledProperty<double> ViewportCenterYProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(nameof(ViewportCenterY), 0.0d);
+        public double ViewportCenterY { get => GetValue(ViewportCenterYProperty); set => SetValue(ViewportCenterYProperty, value); }
+
+        public StyledProperty<double> ViewportCenterXProperty = AvaloniaProperty.Register<CustomDrawingExampleControl, double>(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;
+        }
+    }
+}

+ 1 - 0
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@@ -14,6 +14,7 @@
     <PackageReference Include="MicroCom.CodeGenerator.MSBuild" Version="0.11.0" PrivateAssets="all" />
     <PackageReference Include="MicroCom.CodeGenerator.MSBuild" Version="0.11.0" PrivateAssets="all" />
     <MicroComIdl Include="WinRT\winrt.idl" CSharpInteropPath="WinRT\WinRT.Generated.cs" />
     <MicroComIdl Include="WinRT\winrt.idl" CSharpInteropPath="WinRT\WinRT.Generated.cs" />
     <MicroComIdl Include="Win32Com\win32.idl" CSharpInteropPath="Win32Com\Win32.Generated.cs" />
     <MicroComIdl Include="Win32Com\win32.idl" CSharpInteropPath="Win32Com\Win32.Generated.cs" />
+    <MicroComIdl Include="DirectX\directx.idl" CSharpInteropPath="DirectX\directx.Generated.cs" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Compile Remove="..\..\Shared\ModuleInitializer.cs" />
     <Compile Remove="..\..\Shared\ModuleInitializer.cs" />

+ 139 - 0
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)),
+    }
+}

+ 1370 - 0
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<DXGI_RGB> 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
+}

+ 29 - 0
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);
+    }
+}

+ 202 - 0
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<TimeSpan>? 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<IDXGIFactory>(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<IDXGIAdapter>(adapterPointer, true);
+                void* outputPointer = null;
+                ushort outputIndex = 0;
+                while (adapter.EnumOutputs(outputIndex, &outputPointer) == 0)
+                {
+                    using var output = MicroComRuntime.CreateProxyFor<IDXGIOutput>(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<bool>();
+            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<IRenderTimer>().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
+}

+ 184 - 0
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<IUnknown>(((AngleWin32EglDisplay)_egl.Display).GetDirect3DDevice(), false);
+
+            _dxgiDevice = pdevice.QueryInterface<IDXGIDevice>();
+
+            // 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<IDXGIFactory2>(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<IUnknown>(_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
+}

+ 32 - 0
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);
+            }
+        }
+    }
+}

+ 305 - 0
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);
+}
+

+ 5 - 0
src/Windows/Avalonia.Win32/Win32GlManager.cs

@@ -2,6 +2,7 @@ using Avalonia.OpenGL;
 using Avalonia.OpenGL.Angle;
 using Avalonia.OpenGL.Angle;
 using Avalonia.OpenGL.Egl;
 using Avalonia.OpenGL.Egl;
 using Avalonia.Platform;
 using Avalonia.Platform;
+using Avalonia.Win32.DxgiSwapchain;
 using Avalonia.Win32.OpenGl;
 using Avalonia.Win32.OpenGl;
 using Avalonia.Win32.WinRT.Composition;
 using Avalonia.Win32.WinRT.Composition;
 
 
@@ -49,6 +50,10 @@ namespace Avalonia.Win32
                     {
                     {
                         WinUICompositorConnection.TryCreateAndRegister(egl, opts.CompositionBackdropCornerRadius);
                         WinUICompositorConnection.TryCreateAndRegister(egl, opts.CompositionBackdropCornerRadius);
                     }
                     }
+                    else if (opts.UseLowLatencyDxgiSwapChain)
+                    {
+                        DxgiConnection.TryCreateAndRegister(egl);
+                    }
                 }
                 }
 
 
                 return egl;
                 return egl;

+ 10 - 0
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
         /// This can be useful when you need a rounded-corner blurred Windows 10 app, or borderless Windows 11 app
         /// </summary>
         /// </summary>
         public float? CompositionBackdropCornerRadius { get; set; }
         public float? CompositionBackdropCornerRadius { get; set; }
+
+        /// <summary>
+        /// When <see cref="UseLowLatencyDxgiSwapChain"/> 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 <see cref="UseWindowsUIComposition"/><br/>
+        /// This is mutually exclusive with 
+        /// <see cref="UseWindowsUIComposition"/> which if active will override this setting. 
+        /// </summary>
+        public bool UseLowLatencyDxgiSwapChain { get; set; } = false;
     }
     }
 }
 }
 
 

+ 17 - 0
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -26,6 +26,7 @@ using static Avalonia.Win32.Interop.UnmanagedMethods;
 using Avalonia.Collections.Pooled;
 using Avalonia.Collections.Pooled;
 using Avalonia.Metadata;
 using Avalonia.Metadata;
 using Avalonia.Platform.Storage;
 using Avalonia.Platform.Storage;
+using Avalonia.Win32.DxgiSwapchain;
 
 
 namespace Avalonia.Win32
 namespace Avalonia.Win32
 {
 {
@@ -63,6 +64,7 @@ namespace Avalonia.Win32
         private Thickness _offScreenMargin;
         private Thickness _offScreenMargin;
         private double _extendTitleBarHint = -1;
         private double _extendTitleBarHint = -1;
         private bool _isUsingComposition;
         private bool _isUsingComposition;
+        private bool _isUsingDxgiSwapchain;
         private IBlurHost _blurHost;
         private IBlurHost _blurHost;
         private PlatformResizeReason _resizeReason;
         private PlatformResizeReason _resizeReason;
         private MOUSEMOVEPOINT _lastWmMousePoint;
         private MOUSEMOVEPOINT _lastWmMousePoint;
@@ -143,6 +145,16 @@ namespace Avalonia.Win32
                     egl.Display is AngleWin32EglDisplay angleDisplay &&
                     egl.Display is AngleWin32EglDisplay angleDisplay &&
                     angleDisplay.PlatformApi == AngleOptions.PlatformApi.DirectX11;
                     angleDisplay.PlatformApi == AngleOptions.PlatformApi.DirectX11;
 
 
+            DxgiConnection dxgiConnection = null;
+            if (!_isUsingComposition)
+            {
+                dxgiConnection = AvaloniaLocator.Current.GetService<DxgiConnection>();
+                _isUsingDxgiSwapchain = dxgiConnection is { } &&
+                    glPlatform is EglPlatformOpenGlInterface eglDxgi &&
+                        eglDxgi.Display is AngleWin32EglDisplay angleDisplayDxgi &&
+                        angleDisplayDxgi.PlatformApi == AngleOptions.PlatformApi.DirectX11;
+            }
+
             _wmPointerEnabled = Win32Platform.WindowsVersion >= PlatformConstants.Windows8;
             _wmPointerEnabled = Win32Platform.WindowsVersion >= PlatformConstants.Windows8;
 
 
             CreateWindow();
             CreateWindow();
@@ -159,6 +171,11 @@ namespace Avalonia.Win32
 
 
                     _isUsingComposition = true;
                     _isUsingComposition = true;
                 }
                 }
+                else if (_isUsingDxgiSwapchain)
+                {
+                    var dxgigl = new DxgiSwapchainWindow(dxgiConnection, this);
+                    _gl = dxgigl;
+                }
                 else
                 else
                 {
                 {
                     if (glPlatform is EglPlatformOpenGlInterface egl2)
                     if (glPlatform is EglPlatformOpenGlInterface egl2)