microsoft / microsoft-ui-xaml

WinUI: a modern UI framework with a rich set of controls and styles to build dynamic and high-performing Windows applications.
MIT License
6.38k stars 683 forks source link

Mica get's overdrawn by Swapchain when Swapchain covers entire screen #10180

Open marcelwgn opened 6 days ago

marcelwgn commented 6 days ago

Describe the bug

Consider the following scenario where we create a CanvasSwapchainPanel from Win2D while the Window has Mica as backdrop:

<Window
    x:Class="App3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App3"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:xaml="using:Microsoft.Graphics.Canvas.UI.Xaml"
    mc:Ignorable="d">

    <Window.SystemBackdrop>
        <MicaBackdrop />
    </Window.SystemBackdrop>

    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <xaml:CanvasSwapChainPanel x:Name="Swappy" 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch"
            SizeChanged="Swappy_SizeChanged"/>
    </Grid>
</Window>
public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();
    }

    CanvasSwapChain csc;

    private void Swappy_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        this.csc = new CanvasSwapChain(CanvasDevice.GetSharedDevice(), Math.Max((float)Swappy.ActualWidth, 1), Math.Max((float)Swappy.ActualHeight, 1), 96);
        this.Swappy.SwapChain = this.csc;
        DrawInPanel();
    }

    private void DrawInPanel()
    {
        using (var ds = this.csc.CreateDrawingSession(Microsoft.UI.Colors.Transparent))
        {
            ds.Clear(Microsoft.UI.Colors.Transparent);
            ds.DrawText("Some text", 0, 0, Microsoft.UI.Colors.Red);
            ds.DrawRectangle(0, 0, 100, 100, Microsoft.UI.Colors.Red);
        }
        this.csc.Present(0);
    }
}

With this, the output looks like this: Screenshot of black window

However if we change the Grid or the CanvasSwapChainPanel to have a margin or padding of 1 in any of the directions, like this:

[...]
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,1">
[...]

Mica works: Screenshot of Mica working

To add to the unusualness, when one sets the margin and padding of the Grid and CSCP to cancel out like this:

    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="0,0,0,-1">
        <xaml:CanvasSwapChainPanel x:Name="Swappy" 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch"
            Margin="0,0,0,1"
            SizeChanged="Swappy_SizeChanged"/>
    </Grid>

Mica doesn't work anymore: Screenshot of black window

Note that sometimes, the screen only turns black after resizing the window.

Steps to reproduce the bug

Repro project: Mica repro.zip

  1. Create a project and add Win2D as dependency
  2. Add the following XAML:

    <Window
    x:Class="App3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App3"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:xaml="using:Microsoft.Graphics.Canvas.UI.Xaml"
    mc:Ignorable="d">
    
    <Window.SystemBackdrop>
        <MicaBackdrop />
    </Window.SystemBackdrop>
    
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <xaml:CanvasSwapChainPanel x:Name="Swappy" 
            HorizontalAlignment="Stretch" 
            VerticalAlignment="Stretch"
            SizeChanged="Swappy_SizeChanged"/>
    </Grid>
    </Window>
  3. Add the following C#

    public sealed partial class MainWindow : Window
    {
    public MainWindow()
    {
        this.InitializeComponent();
    }
    
    CanvasSwapChain csc;
    
    private void Swappy_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        this.csc = new CanvasSwapChain(CanvasDevice.GetSharedDevice(), Math.Max((float)Swappy.ActualWidth, 1), Math.Max((float)Swappy.ActualHeight, 1), 96);
        this.Swappy.SwapChain = this.csc;
        DrawInPanel();
    }
    
    private void DrawInPanel()
    {
        using (var ds = this.csc.CreateDrawingSession(Microsoft.UI.Colors.Transparent))
        {
            ds.Clear(Microsoft.UI.Colors.Transparent);
            ds.DrawText("Some text", 0, 0, Microsoft.UI.Colors.Red);
            ds.DrawRectangle(0, 0, 100, 100, Microsoft.UI.Colors.Red);
        }
        this.csc.Present(0);
    }
    }
  4. Observe Mica not working

Expected behavior

Mica should work without having to set a margin somewhere.

Screenshots

No response

NuGet package version

WinUI 3 - Windows App SDK 1.6.3: 1.6.241114003

Windows version

No response

Additional context

Windows version 24H2: 26100.2314

codendone commented 6 days ago

Swapchains in WinUI3 are expected to be opaque (because they are drawn by the compositor below other XAML content). The compositor is likely optimizing the case where the Mica is fully obscured by opaque content.