microsoft / WPFDXInterop

Repo for WPF DX Interop support
MIT License
307 stars 98 forks source link

Combining D3D11Image with SharpDX #10

Open PetrMahdalicek opened 8 years ago

PetrMahdalicek commented 8 years ago

Hi, I want to combine D3D11Image with SharpDX. I think it should be possible but I can not figure out how to properly implement OnRender handler. In Render event handler I receive IntPtr. Can you please describe what this argument represents and how should I use it to create render target view?

this is my implementation of Render event handler.

void DoRender(IntPtr pointer) { var dxgiResource = SharpDX.DXGI.Resource.FromPointer(pointer); var dx10Resource = Device.OpenSharedResource(dxgiResource.SharedHandle); var dx10Texture = dx10Resource.QueryInterface(); var renderTarget = new SharpDX.Direct3D10.RenderTargetView(Device, dx10Texture);

    }

Is there anything obviously wrong? I tried to mimic implementation from D3DVisualization.cpp

Thank you Petr

shmuelie commented 8 years ago

I got it working with SharpDX and this is my OnRender

        private void OnRender(IntPtr handle)
        {
            if (rt == null)
            {
                SharpDX.ComObject r = new SharpDX.ComObject(handle);
                SharpDX.DXGI.Resource rgi = r.QueryInterface<SharpDX.DXGI.Resource>();
                SharpDX.Direct3D10.Texture2D t = rgi.QueryInterface<SharpDX.Direct3D10.Texture2D>();
                using (var surface = t.QueryInterface<SharpDX.DXGI.Surface>())
                {
                    var properties = new RenderTargetProperties();
                    properties.DpiX = 96;
                    properties.DpiY = 96;
                    properties.MinLevel = FeatureLevel.Level_DEFAULT;
                    properties.PixelFormat = new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.Unknown, AlphaMode.Premultiplied);
                    properties.Type = RenderTargetType.Default;
                    properties.Usage = RenderTargetUsage.None;
                    rt = new RenderTarget(new Factory(), surface, properties);
                }
            }
            if (brush == null)
            {
                brush = new SharpDX.Direct2D1.SolidColorBrush(rt, new SharpDX.Color4(0.2f, 0.2f, 0.2f, 0.5f));
            }
            rt.BeginDraw();
            rt.DrawTextLayout(new SharpDX.Vector2(50, 50), tl, brush);
            rt.EndDraw();
        }

tl is a TextLayout

rrelyea commented 8 years ago

Would be great if somebody could put together a new sample that shows SharpDx integration with the WPF DirectX extensions.

shmuelie commented 8 years ago

My experience in SharpDX is with the Direct2D and DirectWrite APIs, so maybe better if someone knowing how to use the 3D APIs does the sample.

QuantumDeveloper commented 8 years ago

The issue here is that on each OnRender() call it send and IntPtr, which is incorrect by itself. It shoud send it only once during creation and IntPtr should not change during the whole lifecycle. But here we receive it each call and must recreate all resources each frame or at least check is IntPtr has changed. It is not efficient way of working. Resources must not be recreated each frame and this is the major issue with DirectX extensions. Until this be fixed, there is no sense to do any samples based on it.

PetrMahdalicek commented 8 years ago

Hello Samuel, thank You, You pushed me into the right direction.

I got it working(at least I'm able to clear back buffer), here is my Render handler:

private void DoRender(IntPtr handle) { var device = this.Device;

        if (_renderTargetView == null)
        {
            SharpDX.DXGI.Resource dxgiResource;
            using (var r = new SharpDX.ComObject(handle))
            {
                dxgiResource = r.QueryInterface<SharpDX.DXGI.Resource>();
            }

            var directx11Resource = device.OpenSharedResource<SharpDX.Direct3D11.Resource>(dxgiResource.SharedHandle);
            var directx11Texture = directx11Resource.QueryInterface<SharpDX.Direct3D11.Texture2D>();

            var desc = new RenderTargetViewDescription();
            desc.Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm;
            desc.Dimension = RenderTargetViewDimension.Texture2D;
            desc.Texture2D.MipSlice = 0;

            _renderTargetView = new RenderTargetView(device, directx11Resource);
        }

        device.ImmediateContext.OutputMerger.SetRenderTargets(_renderTargetView);
        device.ImmediateContext.ClearRenderTargetView(_renderTargetView, new Color4(1.0f, 0.0f, 0.0f, 1.0f));

        device.ImmediateContext.Flush();            
    }
PetrMahdalicek commented 8 years ago

I put together extremely simple example: https://www.dropbox.com/s/oq4am24f24kfyq1/sharpdx11Test.zip?dl=0

shmuelie commented 8 years ago

@QuantumDeveloper you don't need to recreate the resources every frame. In my experiments I only recreate resources on resize.

QuantumDeveloper commented 8 years ago

@SamuelEnglard I am using D3D and swapchain. For swapchain I need window/control handler to tell swpachain where to output image. With current D3DImage implementation when Intptr is changed I need to recreate whole swapchain with all bounded resources to correctly output an image. On resize this pointer also changed (but it should not) so, this is extremely unefficient as a result, because window handle could change at any time, but actually it should be the same all the lifecycle. Windows doesnt change their handles when resizing, Am I right?

shmuelie commented 8 years ago

@QuantumDeveloper I agree that I'd prefer to not have to recreate resources. Currently though I have to recreate resources on resize without this (using custom interop here) so that's not a huge deal to me.

holance commented 7 years ago

@PetrMahdalicek HelixToolkit SharpDX uses SharpDX for rendering. Would be a good reference to begin with.