martinrhan
martinrhan

Reputation: 493

Trying to use the graphics composition feature of AvaloniaUI with DirectX 11, but I cannot render my ID3D11Texture2D into Avalonia visual

I created following class and set it as content of the MainWindow.

public class DXControl : Control{
    static IDXGIFactory7 DXGIFactory = DXGI.CreateDXGIFactory1<IDXGIFactory7>();
    static ID2D1Factory D2D1Factory = D2D1.D2D1CreateFactory<ID2D1Factory>();

    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) {
        int imageWidth = 1024;
        int imageHeight = 1024;

        ID3D11Device3 d3d11Device = D3D11.D3D11CreateDevice(DriverType.Hardware, DeviceCreationFlags.BgraSupport, Vortice.Direct3D.FeatureLevel.Level_11_1).QueryInterface<ID3D11Device3>();

        ID3D11Texture2D texture = d3d11Device.CreateTexture2D1(new() {
            Format = Format.R8G8B8A8_UNorm,
            Width = (uint)imageWidth,
            Height = (uint)imageHeight,
            ArraySize = 1,
            MipLevels = 1,
            SampleDescription = SampleDescription.Default,
            BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource,
            Usage = ResourceUsage.Default,
            CPUAccessFlags = CpuAccessFlags.None,
            MiscFlags = ResourceOptionFlags.SharedNTHandle | ResourceOptionFlags.SharedKeyedMutex,
            TextureLayout = TextureLayout.Undefined
        });

        IDXGIDevice dxgiDevice = d3d11Device.QueryInterface<IDXGIDevice>();

        ID2D1RenderTarget renderTarget = D2D1Factory.CreateDxgiSurfaceRenderTarget(
            texture.QueryInterface<IDXGISurface>(),
            new() {
                Type = RenderTargetType.Hardware,
                PixelFormat = new(Format.Unknown, Vortice.DCommon.AlphaMode.Ignore),
                Usage = RenderTargetUsage.None,
                MinLevel = Vortice.Direct2D1.FeatureLevel.Default,
                DpiX = 0,
                DpiY = 0
            }
            );
        renderTarget.BeginDraw();
        renderTarget.Clear(new(0xFF0000FF));
        renderTarget.EndDraw();

        IDXGIResource1 dxgiResource1 = texture.QueryInterface<IDXGIResource1>();
        IntPtr ptr = dxgiResource1.CreateSharedHandle(null, Vortice.DXGI.SharedResourceFlags.Read, null);
        PlatformHandle platformHandle = new(ptr, KnownPlatformGraphicsExternalImageHandleTypes.D3D11TextureNtHandle);

        Compositor compositor = ElementComposition.GetElementVisual(this)!.Compositor;
        var task = compositor.TryGetCompositionGpuInterop();
        ICompositionGpuInterop? gpuInterop = task.Result;
        if (gpuInterop is null) return;
        ICompositionImportedGpuImage importedImage = gpuInterop.ImportImage(
            platformHandle,
            new() {
                Format = PlatformGraphicsExternalImageFormat.R8G8B8A8UNorm,
                Width = imageWidth,
                Height = imageHeight,
                MemoryOffset = 0,
                MemorySize = (ulong)(imageWidth * imageHeight * sizeof(uint)),
                TopLeftOrigin = true
            }
            );

        CompositionSurfaceVisual visual = compositor.CreateSurfaceVisual();
        visual.Size = new(Bounds.Width, Bounds.Height);
        CompositionDrawingSurface compositionDrawingSurface = compositor.CreateDrawingSurface();
        visual.Surface = compositionDrawingSurface;
        compositionDrawingSurface.UpdateAsync(importedImage).ContinueWith(task => Debug.WriteLine("Update Completed"));

        ElementComposition.SetElementChildVisual(this, visual);        
    }
}

The window can startup without any exception. However, the texture which was fill with red color wasn't present. I checked the example provided in https://github.com/AvaloniaUI/Avalonia/tree/master/samples/GpuInterop/D3DDemo and I cannot figure out where is problem of my code.

Upvotes: 0

Views: 54

Answers (0)

Related Questions