smourier/DirectN

Is it possible to display IDComposition Visual or Windows.UI.Composition.Visual in WinUI3

selastingeorge opened this issue · 30 comments

Hi, i was developing a project based on Win UI 3, i was trying to display and IDCompositionVisual (or Windows.UI.Composition.Visual) into WinUI3 Desktop Application without airspace issue. is it possible to do it using DirectN or in any other possible way ?

Hi,

IDCompositionVisual is an "old" thing (Dcomp V1/V2) that is supported by Win32 (and WinRT).
Windows.UI.Composition.Visual is more recent (Dcomp V3) but reserved for WinRT.

Both are supported by a Windows-only Dll: %windir%\system32\Dcomp.dll

I'm not expert enough in WinUI 3 but my understanding is it comes with its own "Dcomp" which is in a Microsoft namespace: Microsoft.UI.Composition.Visual (https://docs.microsoft.com/en-us/windows/winui/api/microsoft.ui.composition.visual) in a specific .dll (Dcompi.dll) also associated with a custom DWM that are shipped with the Win UI 3 runtime or packaged with your WinUI 3 app.

So, in the end what it means is:

  • If you use IDCompositionVisual, you can use DirectN
  • If you use Windows.UI.Composition.Visual you don't need DirectN (unless you need to access other interfaces such as Direct2D since Composition doesn't provide a way to render only to compose) you can use C#/WinRT with .NET 5
  • If you use WinUI 3, you shouldn't need DirectN either

Since Microsoft has Decoupled from OS Microsoft.UI.Composition stops supporting most of the functionalities that Windows.UI.Composition supports (like interop). IDComposition is an old thing but in most part of windows 10 they are using the same thing. For example you can take the DWM Thumbnail, Even the Acrylic Effect internal uses this IDCompositionVisual, i just recreated the Windows Acrylic Effect on Win32 using DWM Thumbnail, but I need a Way to render it into a Win UI Window or at least WPF without airspace issue. I tried most of the methods and none of them are working.

Here is my Current Project Win32-Acrylic-Effect

After Some research I think, it might be possible to do so in WPF, i was able to hook to WPF SwapChain and I was able to control the WPF Swap chain. The WPF SwapChain is of type IDirect3DSwapChain9, so if it is possible to get the back buffer into an ID2D1Bitmap (using Surface Queueing mentioned over Here ) it is possible to render the WPF Content on top of Direct Composition. But i haven't found a single sample to do this.

Direct Composition is indeed tightly coupled with the DWM.

Your code uses a lot of undocumented functions. You don't need to use any undocumented function to get the true acrylic effect. You only need WinRT's Windows.UI.Composition (and connect the dots as it's not super documented outside of UWP sandboxed crap):

Compositor.CreateHostBackdropBrush:
https://docs.microsoft.com/en-us/uwp/api/windows.ui.composition.compositor.createhostbackdropbrush

Compositor.CreateBackdropBrush
https://docs.microsoft.com/en-us/uwp/api/windows.ui.composition.compositor.createbackdropbrush

And then, the exact recipe for the effect graph is here https://github.com/microsoft/microsoft-ui-xaml/blob/main/dev/Materials/Acrylic/AcrylicBrush.cpp#L697

Unfortunately, IDComposition doesn't have these methods, they're only available with WinRT which is not anymore a problem today since many WinRT APIs are accessible to regular unpackaged Win32 desktop apps. So IDComposition is not from a public API point of view the same as Windows.UI.Composition. Although they are technically both implemented in dcomp.dll, there are things that you can only do with WinRT Windows.UI.Composition.

As for WPF, I the problem to me is really the fact they're hooked on DX9. Maybe you can do it, but only with severe hacking.

I have all that working fine with .NET and DirectN w/o any undocumented function (I can't today paste the code here because it's proprietary, but there are plans to do so). And once you start using Windows.UI.Composition, you don't need to touch IDComposition at all.

But the problem is when i use Windows.UI.Composition 's CreateHostBackdropBrush() in win32 Apps it only produces BLACK Rectangle instead of The host Backdrop. it's mentioned over Here

The main issue is the flickering of Window while resizing. Compared to Windows.UI.Composition in win32 apps IDComposition has less Flickering on resize. The flickering still exist in WinUI3.

The WinUI3 looks a bit complicated, it is even difficult to get just the HWND from a C++ WinUI3 Project.

Suppose, even if I created the Acrylic Effect using Windows.UI.Composition, till now no one haven't found any way to host it into winUI application,

Yes, for CreateHostBackdropBrush to not be black you do need to enable blur behind on the window, something like this with DirectN C#:

        var accent = new ACCENT_POLICY();
        accent.AccentState = ACCENT_STATE.ACCENT_ENABLE_BLURBEHIND;
        var data = new WINDOWCOMPOSITIONATTRIBDATA();
        data.dwAttrib = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY;
        using (var mem = new ComMemory(accent))
        {
            data.cbData = new IntPtr(mem.Size);
            data.pvData = mem.Pointer;
            WindowsFunctions.SetWindowCompositionAttribute(hwnd, ref data).ThrowOnError();
        }

About flickering, I don't know, I have zero flickering with Windows.UI.Composition. I don't use any swap chain, you don't need any with Windows.UI.Composition, check this great seminal sample: https://gist.github.com/kennykerr/62923cdacaba28fedc4f3dab6e0c12ec. There's no reason there should be any flickering.

As for hosting in WinUI 3, as I said, I've not investigated it so far because it's not really finished (it still needs packaging and tooling as compilation times are awful, showstopper for me). In fact I've written my own WPF/WinUI3-like framework in C# because of all these reasons.

Hi, i Checkout, it's working fine and it is same as the Acrylic Effect that i have created. the private dwm api that i used is the same which they used here in CreateHostBackdropBrush(). Because this acrylic effect also wont update when the window is not activated, like the one that i built.

See this :
image

Both uses the DWM Private API's, but when using direct composition the flickering is lesser compared to Windows.UI.Composition, but it it is unable to apply AtlasEffect in DirectComposition.

I got the DWM Private functions when i decompiled the dwmapi.dll and searched for DWMEnableBlurBehindWindow().

If there was any way to copy the content from IDCompositionVisual to ID2D1Bitmap, WinUI3 can support Acrylic and transparency.

Well, in my case, beyond the ACCENT_ENABLE_BLURBEHIND undocumented hack, I use only public API, WinRT's Windows.UI.Composition, and Direct2D (with DirectN, not with the Win2D UWP-only crap), and have no problem with deactivated windows nor flickering.

Here is a .NET Framework 4.8 C# sample:
Acrylic

Open any Window like mspaint, Maximize it , open your acrylic window, maximize that too, then restore the paint window the acrylic window wont update. Microsoft has introduced a new DWMWINDOWATTRIBUTE called DWMWA_USE_HOSTBACKDROPBRUSH, so i think ACCENT_ENABLE_BLURBEHIND will not be needed anymore, currently it is only supported in InsderPreview.

I use only public API, WinRT's Windows.UI.Composition, and Direct2D

Is it possible to share the Windows.UI.Composition.Visual With Direct2D ?

Not sure what problem you have, like I said, I have zero issue.

2021-06-21_11-55-23.mp4

To use Direct2D with Windows.UI.Composition.Visual you need to

  • create a SpriteVisual
  • create a CompositionDrawingSurface from CompositionGraphicsDevice.CreateDrawingSurface
  • associate a CompositionSurfaceBrush (Compositor.CreateSurfaceBrush) to the SpriteVisual Brush
  • then you can cast the CompositionDrawingSurface as a ICompositionDrawingSurfaceInterop
  • call ICompositionDrawingSurfaceInterop.BeginDraw
  • the updateObject you get from BeginDraw can be cast into an ID2D1DeviceContext
  • use that ID2D1DeviceContext the way you want
  • call ICompositionDrawingSurfaceInterop.EndDraw

That's why you don't need any swapchain. You use the DWM/Dcomp one implicitely

You have done that wrong, try this
It is possible to draw Direct2D Contents on to visual, but i was looking to do it in reverse, i need the Windows.UI.Composition.Visual into an ID2D1Bitmap.

Whatever I try, it works fine:

2021-06-21_14-42-46.mp4

As for the other question, it don't think you can do this. The logic is the calling developer sets a given visual's content, so he should know what it contains and doesn't need to read it back.

In one of my WPF project i created, i was able to get the IDirect3DSwapChain9 from my WPF app through hooking. i was able to get the Back buffer from the Swap chain, will it be possible for me to copy it into IDComposition Visual or Windows.UI.Composition.Visual. I have heard about a method called Shared Surfaces, but i wasn't able to find any code on it. i read about it on surface-sharing-between-windows-graphics-apis, So if it was possible i can just copy the content of swapchain to a visual and render it top on Acrylic Right?, it could avoid airspace issue in wpf.

WPF is based on dcomp/d2d/wic primitive ancestors. Even if you can do it, there can be sync issues I guess. Real "sharing", not "copying" seems the way to go to avoid flickering, but I don't think you can do achieve it with WPF. Maybe if you hook everything you can manage to do something, but there's nothing sure I think. One of the best description (w/o solution...) of all this is here from a Microsoft guy: https://dwayneneed.github.io/wpf/2013/02/26/mitigating-airspace-issues-in-wpf-applications.html

Looks like i am at another dead end. Any way thank you very much for sharing your knowledge. Will there be any other way that i could contact you like discord or something, just for resolving doubts, if any.

I am closing this issue, Thank you

Thank you, i will drop a question if i have doubts.

Whatever I try, it works fine:

2021-06-21_14-42-46.mp4
As for the other question, it don't think you can do this. The logic is the calling developer sets a given visual's content, so he should know what it contains and doesn't need to read it back.

Hi can you please share the code that you used here?

The code is currently proprietary. But it will be made public hopefully in the next week(s). I'll keep you posted

Hi could you please clear one doubt, I was using Windows.UI.Composition to create acrylic in my app, to avoid airspace issue, I overlaid Windows (one foreground window - With my controls, One background window with acrylic) I resize the background window along with foreground and all window animations work well except the minimize animation, I need to hide my Background Window from taskbar and alt+tab, but using WS_EX_NOACTIVE will minimize Window to the bottom left corner of desktop and using WS_EX_TOOLWINDOW will remove the animations, so I used ITaskbarList3 interface and used deleteTab() function, and this works perfectly and hides the window from taskbar and alt+tab, but during minimize the window is minimized to taskbar but to some other location (exactly to bottom right corner in my system), it's looks like the window is scaling up instead of scaling down. but in another pc it is minimizing to correct position but not shrinking the window size.
Checkout these screenshots:

image

Using WS_EX_NOACTIVATE

2021-08-24.14-37-10.mp4

(Here I slowed down the DWM animation using registry tweak to see what exactly is happening)
Here is the result when i tested it on a good performance computer, it minimize to correct location but the size is not changing,
In my Computer the window size is increasing and it is minimizing to the bottom right corner near to the battery indicator.

Here is the another Case :

nw.mp4

(the flickering of acrylic is just in screen recorder otherwise, it's fine)
is there any way that i could change the location to which window is minimized.

I'm not sure how I can help you here :-) This seems specific to what you do. Anyway the code I use is now public: https://github.com/aelyo-softworks/Wice

Thankyou, i will try to find another way around. The project you mentioned, is it like a wpf project but renders everything using Windows.UI.Composition

It's similar to WPF in many ways yes (but different in others like no XAML), and uses Windows.UI.Composition at its core, and Direct2D for what DComp can't do (bitmaps, texts, etc.).

let me try it out

image
Wow it looks Great, you have built all the controls from scratch, including the button on title bar.

This is one similar to your project but uses Direct Composition Instead of Windows.UI.Composition,https://github.com/ByteJammer/Win11RCT

It sure looks nice on your Windows 11 background :-) More samples will be added to the gallery in the next days hopefully.